6

まず第一に、私はマニュアルとphpのドキュメントを掘り下げて答えを見つけられなかったことを言及する必要があります. 私が使用するコードは次のとおりです。

class chomik {

    public $state = 'normal';
    public $name = 'no name';

    public function __construct($name) {
        $this->name = $name;
    }

    public function __toString() {
        return $this->name . " - " . $this->state;
    }
}

function compare($a, $b) {
    echo("$a : $b<br/>");
    if($a != $b) {
        return 0;
    }
    else return 1;
}

$chomik = new chomik('a');
$a = array(5, $chomik, $chomik, $chomik);
$b = array($chomik, 'b', 'c', 'd');
array_diff_uassoc($a, $b, 'compare');

私の考えでは、array_diff_uassoc はこれら 2 つの配列のすべての値を比較し、値が存在する場合はキー比較を実行します。このコードの出力は次のとおりです。

1 : 0
3 : 1
2 : 1
3 : 2
1 : 0
3 : 1
2 : 1
3 : 2
3 : 3
3 : 2
2 : 3
1 : 3
0 : 3

ではまず、一部のペア (1 : 0 または 3 : 1) が重複しているのはなぜですか? このアイテムをすでに比較したことを機能が忘れていたということですか?すべての等しい値のペアを比較すると思っていましたが、出力には表示されません。何か不足していますか?

質問は次のとおりです:比較の順序に関して、この関数の正確な動作は何ですか?なぜこの重複が見られるのですか? (私のPHPバージョン、それが役立つ場合:PHPバージョン5.3.6-13ubuntu3.6)

私は本当に混乱していて、それについての良い説明を待っています...

4

3 に答える 3

0

opコメントから

2 番目の配列 ($a[0]) にないこれらの要素のみが必要です

使えませんarray_diff($a, $b);か?戻ります

array(1) {
  [0]=>
  int(5)
}

それ以外は、

ドキュメントには次のように記載されています。

比較関数は、最初の引数がそれぞれ 2 番目の引数より小さい、等しい、または大きいと見なされる場合、0 より小さい、等しい、または大きい整数を返さなければなりません。

私が理解しているように、それはcompare()関数が次のようになるべきであることを意味します:

function compare($a, $b) {
    echo("$a : $b<br/>");
    if($a === $b) return 0;
    else if ($a > $b) return 1;
    else return -1;
}

ただし、この修正を行っても、非常に奇妙な比較結果が得られます。

1:0
1:2
3:1
2:1
3:2
1:0
1:2
3:1
2:1
3:2
0:0
1:0
1:1
2:0
2:1
2:2
3:0
3:1
3:2
3:3

回答の範囲を超えていたので、これについて別の質問をしました。

于 2015-04-02T19:58:44.783 に答える
0

戻り値のセクションを見逃したと思います。

他のどの配列にも存在しない、array1 からのすべてのエントリを含む配列を返します。

比較には配列キーが使用されます。

テキストに欠けているのは、比較が連想的にのみ行われていることです。これは、自動的に宣言された数値キーまたはユーザー定義の数値キーが、整数ではなく文字列として入力されることを意味します。

だから

$one = array(a,b,c,'hot'=>d); // d has no match and  will be returned as array and go to the function alone
$two = array(a,b,c,d,e,f); //

$one hot=>d は連想レベルで $two 0=>d と一致しないため、$one hot=>d が返されます。

文字列と整数のデータ型比較の PHP の癖のため、ユーザー定義関数を使用して、=== のようなより強力な比較演算を使用して比較を強化できます。

これは、タイプがあいまいな場合に役立ちます '0'=>d と 0=>d は似ているように見えるかもしれませんが、コードでそう言うまではそうではありません。

幸いなことに、PHP7 には型ヒントが導入され、このような奇妙な構造や不明瞭なドキュメントがなくなりました。

私のコメントからこれを追加します。これは、あなたの場合にどのphpコンストラクトが最もよく使用されるかについての理解に関係するためです。私のコメント:

コード内の if($a != $b) { が問題であるため、それについてはよくわかりません。同一の演算子 !== を使用する必要があるときに、誤って等価を使用しているためです。また、連想キー用に設計された構成で数値キーを使用しています。また、関係するデータにより適した array_udiff を認識していない可能性があります。

于 2015-04-02T20:51:14.937 に答える
0

これは確かにやや興味深いです。私は github で PHP の最新のソース (ご存知のように C++ で書かれています) を調べて、その意味を理解しようとしました。( https://github.com/php/php-src/blob/master/ext/standard/array.c )

クイック検索で、問題の関数が 4308 行で宣言されていることがわかりました

PHP_FUNCTION(array_diff_uassoc)
{
    php_array_diff(INTERNAL_FUNCTION_PARAM_PASSTHRU, DIFF_ASSOC, DIFF_COMP_DATA_INTERNAL, DIFF_COMP_KEY_USER);
}

これは、実際の作業がphp_array_diff関数によって行われていることを示しています。これは、同じファイルの 3938 行目にあります。ここに貼り付けるには少し長くなります。正確には 265 行ですが、必要に応じて調べることができます。

そこが諦めたポイントです。私は C の経験がまったくありません。それを理解しようとするのは遅すぎて疲れています。おそらく値を比較するよりもパフォーマンスが高いため、キーの比較が最初に行われると思いますが、それは単なる推測です。いずれにせよ、彼らがそうするのにはおそらく正当な理由があります。

これは長い紹介にすぎませんが、そもそもなぜ関数のに を入れたいのでしょうechocompareか? の目標はarray_diff_uassoc、関数の出力です。パーサーがそれを処理する方法に依存するべきではありません。彼らが明日、そのC関数の内部動作をieに変更することを決定した場合。最初に値の比較を行うと、まったく異なる結果が得られます。

おそらく、 phpで記述されたこの置換関数を使用できます。

そうすれば、動作が変わらないように頼ることができ、内部の仕組みを完全に制御できます...

于 2015-04-02T21:19:32.917 に答える