2

データベースから配列を受信して​​います。どのデータがどのような順序で送信されるかを制御できません。現在の様子は次のとおりです。

Array
(
    [itemCode] => Array
        (
            [0] => Array
                (
                    [code] => P
                    [descShort] => Pepperoni
                )

            [1] => Array
                (
                    [code] => G
                    [descShort] => Green Peppers
                )

            [2] => Array
                (
                    [code] => n
                    [descShort] => No Sauce
                )

            [3] => Array
                (
                    [code] => x
                    [descShort] => No Cheese
                )

            [4] => Array
                (
                    [code] => 
                    [descShort] => Regular Cheese
                )

            [5] => Array
                (
                    [code] => 
                    [descShort] => Regular Sauce
                )

        )

)

実際には、No Sauce オプションの前に任意の数の要素が存在する可能性があります (現在はインデックス 3 ですが、常にそうであるとは限りません)。クライアントが望むのは、Cheese and Sauce アイテムが常にリストの最後にあり、このように注文しました: レギュラー チーズ、チーズなし、レギュラー ソース、ソースなし。

繰り返しますが、配列が最初にどのように作成されるかを制御することはできず、問題の要素の前と間に他の要素がいくつでも存在する可能性があることを念頭に置いて、どうすればこれを実現できますか? 他に心配すべきことは、ある時点で、この再注文に含めたい他のオプションがある可能性があることです (たとえば、エクストラ チーズとエクストラ ソースのオプションを追加し、それらを特定の位置に配置する必要がある場合があります)。良い。)

var_export を追加

array (
  'itemCode' => 
  array (
    0 => 
    array (
      'code' => 'P',
      'descShort' => 'Pepperoni',
    ),
    1 => 
    array (
      'code' => 'G',
      'descShort' => 'Green Peppers',
    ),

    2 => 
    array (
      'code' => 'n',
      'descShort' => 'No Sauce',
    ),
    3 => 
    array (
      'code' => 'x',
      'descShort' => 'No Cheese',
    ),
    4 => 
    array (
      'code' => '',
      'descShort' => 'Regular Cheese',
    ),
    5 => 
    array (
      'code' => '',
      'descShort' => 'Regular Sauce',
    ),
  ),
)
4

3 に答える 3

3

ユーザー定義の並べ替えを許可するusortを使用してみることができます。

于 2012-11-07T16:57:50.600 に答える
2

すでにコメントされているので、そのためにusort関数を使用することができます。ただし、比較機能が必要なため、これはほんの始まりにすぎません。

作成するだけなので、それほど難しくはありません。ただし、それがどのように機能するかを理解することが重要です。

比較関数は、最初の引数がそれぞれ2番目の引数よりも小さい、等しい、または大きいと見なされる場合、ゼロより小さい、等しい、またはより大きい整数を返す必要があります。

さて、それはブロッカーではありませんが、実際の質問になります。どの方法がどの方法よりも上にあるかを確認する方法は?そして、それをどのように拡張可能にするのですか?

値には、順序付けが不要な値と順序付けが必要な値の2種類があります。まず、順序付けが必要な配列を定義しましょう。そして、その順序が何であるかを明確にするために、キーに名前を付けます。

$order    = 'descShort';
$ordering = ['Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce'];

これで、比較機能内で、A/B値のエントリが注文内に存在するかどうかを調べることができます。存在しない場合は、注文する必要はありません。存在する場合は、注文する必要があります。

これらの2つのケースは、既存のソート順と存在しないソート順を使用できるため、拡張されます。したがって、カバーする4つのケースがあります。

  1. AとBは存在しません-それらを等しく扱います-0
  2. AとBが存在します-それらの順序値に従ってソートします-位置Aを計算します-B
  3. Aは存在するが、Bは存在しない-AはB-1より大きい
  4. Bは存在しますが、Aは存在しません-AはB---1未満です

PHPでの関数サポートのおかげで、簡単な例として、order-keyとordering値を比較関数に簡単に渡すことができます。この場合、関数は4つのケースで概説されていることを実行するだけで済みます。

例:

$order    = 'descShort';
$ordering = ['Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce'];
$compare  = function($a, $b) use ($order, $ordering) {
    $hasA = array_search($a[$order], $ordering);
    $hasB = array_search($b[$order], $ordering);

    // nothing to sort
    if ($hasA === $hasB && $hasA === FALSE) {
        return 0;
    }

    // if both are found, sort
    if ($hasA !== FALSE && $hasB !== FALSE) {
        return $hasA - $hasB;
    }

    // as one of them is in there, put it to end
    return $hasA === FALSE ? -1 : 1;
};

usort($array['itemCode'], $compare);

したがって、注意点が1つありusortます。それは、安定していないということです。つまり、0を返すと、アイテムはその位置に留まりません。を使用して同じようにもう一度並べ替えることで、この問題を回避できますusort

usort($array['itemCode'], $compare);

次に、最終的な並べ替え順序は(デモ)です。

Array
(
    [itemCode] => Array
        (
            [0] => Array
                (
                    [code] => P
                    [descShort] => Pepperoni
                )

            [1] => Array
                (
                    [code] => G
                    [descShort] => Green Peppers
                )

            [2] => Array
                (
                    [code] => 
                    [descShort] => Regular Cheese
                )

            [3] => Array
                (
                    [code] => x
                    [descShort] => No Cheese
                )

            [4] => Array
                (
                    [code] => 
                    [descShort] => Regular Sauce
                )

            [5] => Array
                (
                    [code] => n
                    [descShort] => No Sauce
                )
        )
)

安定ソートに問題があり、私もそれほどうまくいっていないので(ここでは、提案された関数は私にとってオーバーヘッドのように見えます)、古き良きものがありforeachます。

そして、後でソートされる値に重複する値がないので、まあ、これはいくつかの気の利いた余地を残します:

$order    = 'descShort';
$ordering = ['Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce'];

$result = []; // the final result
$later  = []; // to be sorted later
foreach($array as $element)
{

    $has = array_search($element[$order], $ordering);
    if ($has !== FALSE) {
        $later[$has] = $element;
        continue;
    }

    $result[] = $element;
}

配列を処理し、順序付けの一部ではない$resultすべての値をすでに入力します。

$later順序付けの一部であるものは、すでにそれらの順序値をインデックスとして入れられています。

その場合にのみ$later、でソートされksort、2つの部分がマージされます。

ksort($later);
$result = array_merge($result, $later);

そして完了。コールバック関数は必要ありません。最初にフィルタリングするだけで、sort値を使用したインデックス作成がksort魔法のようになります。デモ

于 2012-11-07T17:43:27.543 に答える
0

これはあなたが望むユーザー定義のソートだと思います。配列$last_optionsには、最後まで並べ替える必要のあるすべてのトッピングが一覧表示され、配列内のそれらの順序によって、結果に表示される順序が指定されます。

$last_options = array('Regular Cheese', 'No Cheese', 'Regular Sauce', 'No Sauce');

function topping_order($a, $b) {
  $a_pos = array_search($a['descShort'], $last_options);
  $b_pos = array_search($b['descShort'], $last_options);
  if ($a_pos !== false && $b_pos !== false) {
    if ($a_pos > $b_pos) {
      return 1;
    }
    if ($b_pos > $a_pos) {
      return -1;
    }
    return 0;
  }
  if ($a_pos === false) {
    return -1;
  }
  if ($b_pos === false) {
    return 1;
  }
  return 0;
}

usort($array, 'topping_order');
于 2012-11-07T17:43:31.257 に答える