فرز مصفوفة من المصفوفات متعددة الأبعاد على أكثر من "عمود" (مفتاح) مع خيارات فرز محددة

StackOverflow https://stackoverflow.com/questions/809771

سؤال

أتطلع إلى أن أكون قادرًا على فرز مجموعة من المصفوفات متعددة الأبعاد في أكثر من عمود واحد.ولزيادة تعقيد الأمر، أود أن أكون قادرًا على تعيين خيارات فرز محددة لكل مفتاح/عمود.لدي ما يشبه نتيجة استعلام قاعدة البيانات، ولكنه لا يأتي في الواقع من واحد، وبالتالي هناك حاجة إلى فرزها في PHP بدلاً من SQL.

Array
(
    [0] => Array
        (
            [first_name] => Homer
            [last_name] => Simpson
            [city] => Springfield
            [state] => Unknown
            [zip] => 66735
        )

    [1] => Array
        (
            [first_name] => Patty
            [last_name] => Bouvier
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85250
        )

    [2] => Array
        (
            [first_name] => Moe
            [last_name] => Szyslak
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

    [3] => Array
        (
            [first_name] => Nick
            [last_name] => Riviera
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

)

أود أن أكون قادرًا على فرزها بشكل مشابه لما يمكن فعله باستخدام استعلام قاعدة البيانات.أوه، وأحيانًا يجب تحديد العمود/المفتاح حسب الرقم.

ما كان يدور في ذهني كان شيئًا مشابهًا لهذا:

$sortOptions = array( array( 'city', SORT_ASC, SORT_STRING ),
                      array( 'zip', SORT_DESC, SORT_NUMERIC),
                      array( 2, SORT_ASC, SORT_STRING) // 2='last_name'
                    );
$sorter = new MultiSort($data, $sortOptions );
$sortedData = $sorter->getSortedArray() ;
print_r( $jmsSorted);

ما أود أن ينتهي به الأمر هو هذا:

Array
(
    [0] => Array
        (
            [first_name] => Nick
            [last_name] => Riviera
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

    [1] => Array
        (
            [first_name] => Moe
            [last_name] => Szyslak
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85255
        )

    [2] => Array
        (
            [first_name] => Patty
            [last_name] => Bouvier
            [city] => Scottsdale
            [state] => Arizona
            [zip] => 85250
        )

    [3] => Array
        (
            [first_name] => Homer
            [last_name] => Simpson
            [city] => Springfield
            [state] => Unknown
            [zip] => 66735
        )

)

تحديث: أعتقد أن الحل المثالي سيؤدي إلى إنشاء ديناميكي

array_multisort( $city, SORT_ASC, SORT_STRING, $zip, SORT_DESC, SORT_NUMERIC, $last_name, SORT_ASC, SORT_STRING, $inputArray);

المشكلة هي أنني لا أريد أن أضطر إلى "ترميز" تلك الأسماء الرئيسية هناك.حاولت إنشاء حل يعتمد على المثال رقم 3 فرز نتائج قاعدة البيانات من array_multisort() الوثائق التي انتهى بها الأمر باستخدام array_multisort() لكن يبدو أنني لا أستطيع إيجاد طريقة لاستخدام قائمة الوسائط المبنية ديناميكيًا array_multisort().

كانت محاولتي هي "ربط" تلك الوسائط معًا في مصفوفة ثم

call_user_func_array( 'array_multisort', $functionArgs);

وينتج عن ذلك

Warning: Parameter 2 to array_multisort() expected to be a reference, value given in...
هل كانت مفيدة؟

المحلول 4

هذا ما استقرت عليه أخيرًا لقدرتي على فرز المصفوفات متعددة الأبعاد.كلا الإجابتين أعلاه جيدتان ولكني كنت أبحث أيضًا عن شيء مرن.

أنا بالتأكيد لا أعتقد أن هناك أي إجابة واحدة "صحيحة"، ولكن هذا هو ما يناسب احتياجاتي ويتسم بالمرونة.

كما ترون من بلدي @link في تعليق _usortByMultipleKeys() لقد تم اقتباسه من تعليق في دليل PHP والذي لا يبدو أنه موجود حاليًا، لكنني أعتقد ذلك http://www.php.net/manual/en/function.usort.php#104398 هي نسخة جديدة من التعليق الأصلي.لم أستكشف استخدام هذا الاقتراح الجديد.

/**
 * Sort the resultSet.
 *
 * Usage: $sortOptions = array(
 *          'section', // Defaults to SORT_ASC
 *          'row' => SORT_DESC,
 *          'retail_price' => SORT_ASC);
 *        $results->sortResults($sortOptions);
 *
 * @param array $sortOptions    An array of sorting instructions
 */
public function sortResults(array $sortOptions)
{
    usort($this->_results, $this->_usortByMultipleKeys($sortOptions));
}


/**
 * Used by sortResults()
 *
 * @link http://www.php.net/manual/en/function.usort.php#103722
 */
protected function _usortByMultipleKeys($key, $direction=SORT_ASC)
{
    $sortFlags = array(SORT_ASC, SORT_DESC);
    if (!in_array($direction, $sortFlags)) {
        throw new InvalidArgumentException('Sort flag only accepts SORT_ASC or SORT_DESC');
    }
    return function($a, $b) use ($key, $direction, $sortFlags) {
        if (!is_array($key)) { //just one key and sort direction
            if (!isset($a->$key) || !isset($b->$key)) {
                throw new Exception('Attempting to sort on non-existent keys');
            }
            if ($a->$key == $b->$key) {
                return 0;
            }
            return ($direction==SORT_ASC xor $a->$key < $b->$key) ? 1 : -1;
        } else { //using multiple keys for sort and sub-sort
            foreach ($key as $subKey => $subAsc) {
                //array can come as 'sort_key'=>SORT_ASC|SORT_DESC or just 'sort_key', so need to detect which
                if (!in_array($subAsc, $sortFlags)) {
                    $subKey = $subAsc;
                    $subAsc = $direction;
                }
                //just like above, except 'continue' in place of return 0
                if (!isset($a->$subKey) || !isset($b->$subKey)) {
                    throw new Exception('Attempting to sort on non-existent keys');
                }
                if ($a->$subKey == $b->$subKey) {
                    continue;
                }
                return ($subAsc==SORT_ASC xor $a->$subKey < $b->$subKey) ? 1 : -1;
            }
            return 0;
        }
    };
}

نصائح أخرى

في PHP 5.3، يجب أن تكون كل معلمة في المصفوفة مرجعًا عند الاتصال array_multisort() مع call_user_func_array().

تقوم هذه الوظيفة بفرز مصفوفة متعددة الأبعاد وإظهار طريقة لإنشاء مصفوفة من المعلمات المرجعية التي تعمل بشكل صحيح.

function msort()
{
  $params = func_get_args();
  $array = array_pop($params);

  if (!is_array($array))
    return false;

  $multisort_params = array();
  foreach ($params as $i => $param) 
  {
    if (is_string($param)) 
    {
      ${"param_$i"} = array();
      foreach ($array as $index => $row) 
      {
        ${"param_$i"}[$index] = $row[$param];
      }
    }
    else 
      ${"param_$i"} = $params[$i];

    $multisort_params[] = &${"param_$i"};
  }
  $multisort_params[] = &$array; 

  call_user_func_array("array_multisort", $multisort_params);

  return $array;
}

مثال:

$data هي المصفوفة المحددة من السؤال

$sorted_data = msort('city', SORT_ASC, SORT_STRING, 'zip', SORT_DESC, SORT_NUMERIC, $data)

يجب أن يعمل هذا مع الموقف الذي تصفه.

usort($arrayToSort, "sortCustom");

function sortCustom($a, $b)
{
    $cityComp = strcmp($a['city'],$b['city']);
    if($cityComp == 0)
    {
        //Cities are equal.  Compare zips.
        $zipComp = strcmp($a['zip'],$b['zip']);
        if($zipComp == 0)
        {
            //Zips are equal.  Compare last names.
            return strcmp($a['last_name'],$b['last_name']);
        }
        else
        {
            //Zips are not equal.  Return the difference.
            return $zipComp;
        }
    }
    else
    {
        //Cities are not equal.  Return the difference.
        return $cityComp;
    }
}

يمكنك تكثيفها في سطر واحد مثل هذا:

function sortCustom($a, $b)
{
    return ($cityComp = strcmp($a['city'],$b['city']) ? $cityComp : ($zipComp = strcmp($a['zip'],$b['zip']) ? $zipComp : strcmp($a['last_name'],$b['last_name'])));
}

بقدر ما تتمتع بوظيفة فرز قابلة للتخصيص، فإنك تعيد اختراع العجلة.نلقي نظرة على array_multisort() وظيفة.

قد ترغب في محاولة استخدام com.usort.كل ما عليك فعله هو إنشاء وظائف تخبر القائم بالفرز بكيفية فرزه.تحتوي المستندات على مزيد من المعلومات حول كيفية القيام بذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top