मैं PHP में एक बहुआयामी ऐरे को कैसे क्रमबद्ध करूं




sorting multidimensional-array (8)

परिचय: PHP 5.3+ के लिए एक बहुत ही सामान्यीकृत समाधान

मैं यहां अपना स्वयं का समाधान जोड़ना चाहता हूं, क्योंकि यह उन सुविधाओं की पेशकश करता है जो अन्य उत्तरों नहीं करते हैं।

विशेष रूप से, इस समाधान के फायदों में शामिल हैं:

  1. यह पुन : प्रयोज्य है : आप सॉर्ट कॉलम को हार्डकोडिंग के बजाय चर के रूप में निर्दिष्ट करते हैं।
  2. यह लचीला है : आप कई प्रकार के कॉलम निर्दिष्ट कर सकते हैं (जितना आप चाहते हैं) - अतिरिक्त कॉलम का उपयोग उन वस्तुओं के बीच tiebreakers के रूप में किया जाता है जो प्रारंभ में बराबर तुलना करते हैं।
  3. यह उलटा है : आप निर्दिष्ट कर सकते हैं कि प्रत्येक कॉलम के लिए अलग-अलग प्रकार को अलग किया जाना चाहिए।
  4. यह एक्स्टेंसिबल है : यदि डेटा सेट में कॉलम होते हैं जिन्हें "गूंगा" तरीके से तुलना नहीं किया जा सकता है (उदाहरण के लिए डेट स्ट्रिंग्स) तो आप यह भी निर्दिष्ट कर सकते हैं कि इन आइटम्स को उस मान में कैसे परिवर्तित किया जाए, जिसे सीधे तुलना की जा सकती है (उदाहरण के लिए DateTime इंस्टेंस)।
  5. यदि आप चाहें तो यह सहयोगी है : यह कोड आइटम को सॉर्ट करने का ख्याल रखता है, लेकिन आप वास्तविक सॉर्ट फ़ंक्शन ( usort या uasort ) का चयन करते हैं।
  6. अंत में, यह array_multisort उपयोग नहीं करता है: जबकि array_multisort सुविधाजनक है, यह सॉर्ट करने से पहले आपके सभी इनपुट डेटा का प्रक्षेपण करने पर निर्भर करता है। यह समय और स्मृति का उपभोग करता है और यदि आपका डेटा सेट बड़ा है तो यह केवल निषिद्ध हो सकता है।

कोड

function make_comparer() {
    // Normalize criteria up front so that the comparer finds everything tidy
    $criteria = func_get_args();
    foreach ($criteria as $index => $criterion) {
        $criteria[$index] = is_array($criterion)
            ? array_pad($criterion, 3, null)
            : array($criterion, SORT_ASC, null);
    }

    return function($first, $second) use (&$criteria) {
        foreach ($criteria as $criterion) {
            // How will we compare this round?
            list($column, $sortOrder, $projection) = $criterion;
            $sortOrder = $sortOrder === SORT_DESC ? -1 : 1;

            // If a projection was defined project the values now
            if ($projection) {
                $lhs = call_user_func($projection, $first[$column]);
                $rhs = call_user_func($projection, $second[$column]);
            }
            else {
                $lhs = $first[$column];
                $rhs = $second[$column];
            }

            // Do the actual comparison; do not return if equal
            if ($lhs < $rhs) {
                return -1 * $sortOrder;
            }
            else if ($lhs > $rhs) {
                return 1 * $sortOrder;
            }
        }

        return 0; // tiebreakers exhausted, so $first == $second
    };
}

कैसे इस्तेमाल करे

इस खंड के दौरान मैं इस नमूना डेटा सेट को सॉर्ट करने वाले लिंक प्रदान करूंगा:

$data = array(
    array('zz', 'name' => 'Jack', 'number' => 22, 'birthday' => '12/03/1980'),
    array('xx', 'name' => 'Adam', 'number' => 16, 'birthday' => '01/12/1979'),
    array('aa', 'name' => 'Paul', 'number' => 16, 'birthday' => '03/11/1987'),
    array('cc', 'name' => 'Helen', 'number' => 44, 'birthday' => '24/06/1967'),
);

मूल बातें

फ़ंक्शन make_comparer को परिभाषित करने वाले तर्कों की एक चर संख्या को स्वीकार करता है और एक फ़ंक्शन देता है जिसे आप usort या uasort के तर्क के रूप में उपयोग करना चाहते हैं।

सबसे सरल उपयोग केस उस कुंजी में गुजरना है जिसे आप डेटा आइटम्स की तुलना करने के लिए उपयोग करना चाहते हैं। उदाहरण के लिए, name आइटम द्वारा $data को सॉर्ट करने के लिए आप करेंगे

usort($data, make_comparer('name'));

इसे क्रिया में देखें

यदि आइटम संख्यात्मक रूप से अनुक्रमित सरणी हैं तो कुंजी भी एक संख्या हो सकती है। प्रश्न में उदाहरण के लिए, यह होगा

usort($data, make_comparer(0)); // 0 = first numerically indexed column

इसे क्रिया में देखें

एकाधिक प्रकार के कॉलम

आप make_comparer को अतिरिक्त पैरामीटर पास करके एकाधिक सॉर्ट कॉलम निर्दिष्ट कर सकते हैं। उदाहरण के लिए, "संख्या" द्वारा क्रमबद्ध करें और फिर शून्य-अनुक्रमित कॉलम द्वारा:

usort($data, make_comparer('number', 0));

इसे क्रिया में देखें

उन्नत सुविधाओं

यदि आप एक सरल स्ट्रिंग के बजाय सरणी कॉलम निर्दिष्ट करते हैं तो अधिक उन्नत सुविधाएं उपलब्ध हैं। यह सरणी संख्यात्मक रूप से अनुक्रमित की जानी चाहिए, और इन वस्तुओं को अवश्य रखना चाहिए:

0 => the column name to sort on (mandatory)
1 => either SORT_ASC or SORT_DESC (optional)
2 => a projection function (optional)

चलो देखते हैं कि हम इन सुविधाओं का उपयोग कैसे कर सकते हैं।

रिवर्स सॉर्ट करें

नाम अवरोही द्वारा सॉर्ट करने के लिए:

usort($data, make_comparer(['name', SORT_DESC]));

इसे क्रिया में देखें

संख्या अवरोही और फिर नाम से क्रमबद्ध करने के लिए क्रमबद्ध करें:

usort($data, make_comparer(['number', SORT_DESC], ['name', SORT_DESC]));

इसे क्रिया में देखें

कस्टम अनुमान

कुछ परिदृश्यों में आपको एक कॉलम द्वारा क्रमबद्ध करने की आवश्यकता हो सकती है जिसका मूल्य सॉर्ट करने के लिए अच्छी तरह से उधार नहीं देता है। नमूना डेटा सेट में "जन्मदिन" कॉलम इस वर्णन को फिट करता है: जन्मदिनों को तारों की तुलना करने की समझ में नहीं आता है (उदाहरण के लिए "01/01/1980" "10/10/1970" से पहले आता है)। इस मामले में हम यह निर्दिष्ट करना चाहते हैं कि वास्तविक डेटा को किसी रूप में कैसे प्रोजेक्ट करना है जिसे सीधे वांछित अर्थशास्त्र के साथ तुलना की जा सकती है।

अनुमानों को किसी भी प्रकार के callable रूप में निर्दिष्ट किया जा सकता है: तार, सरणी या अज्ञात फ़ंक्शन के रूप में। एक प्रक्षेपण को एक तर्क स्वीकार करने और इसके अनुमानित रूप को वापस करने के लिए माना जाता है।

यह ध्यान दिया जाना चाहिए कि अनुमानों को usort और परिवार के साथ उपयोग किए जाने वाले कस्टम तुलना कार्यों के समान हैं, लेकिन वे सरल हैं (आपको केवल एक मान को दूसरे में परिवर्तित करने की आवश्यकता है) और make_comparer में पहले से बेक की गई सभी कार्यक्षमताओं का लाभ make_comparer

आइए प्रोजेक्शन के बिना उदाहरण डेटा सेट को सॉर्ट करें और देखें कि क्या होता है:

usort($data, make_comparer('birthday'));

इसे क्रिया में देखें

वह वांछित परिणाम नहीं था। लेकिन हम date_create को प्रक्षेपण के रूप में उपयोग कर सकते हैं:

usort($data, make_comparer(['birthday', SORT_ASC, 'date_create']));

इसे क्रिया में देखें

यह सही क्रम है जिसे हम चाहते थे।

ऐसी कई और चीजें हैं जिनसे अनुमान प्राप्त हो सकते हैं। उदाहरण के लिए, केस-असंवेदनशील प्रकार प्राप्त करने का एक त्वरित तरीका strtolower को प्रक्षेपण के रूप में उपयोग करना है।

उस ने कहा, मुझे यह भी कहना चाहिए कि यदि आपका डेटा सेट बड़ा है तो अनुमानों का उपयोग न करना बेहतर होगा: उस स्थिति में यह आपके सभी डेटा को मैन्युअल रूप से आगे बढ़ाने के लिए बहुत तेज होगा और फिर प्रक्षेपण के बिना सॉर्ट करें, हालांकि ऐसा करने से व्यापार होगा तेजी से क्रम की गति के लिए स्मृति उपयोग में वृद्धि हुई।

अंत में, यहां एक उदाहरण दिया गया है जो सभी सुविधाओं का उपयोग करता है: यह पहली बार संख्या अवरोही से होता है, फिर जन्मदिन आरोही द्वारा:

usort($data, make_comparer(
    ['number', SORT_DESC],
    ['birthday', SORT_ASC, 'date_create']
));

इसे क्रिया में देखें

इस प्रश्न का उत्तर यहां दिया गया है:

मेरे पास एक बहुआयामी सरणी में लोड सीएसवी डेटा है। इस तरह प्रत्येक "पंक्ति" एक रिकॉर्ड होता है और प्रत्येक "कॉलम" में एक ही प्रकार का डेटा होता है। मैं अपनी सीएसवी फ़ाइल लोड करने के लिए नीचे दिए गए फ़ंक्शन का उपयोग कर रहा हूं।

function f_parse_csv($file, $longest, $delimiter)
{
  $mdarray = array();
  $file    = fopen($file, "r");
  while ($line = fgetcsv($file, $longest, $delimiter))
  {
    array_push($mdarray, $line);
  }
  fclose($file);
  return $mdarray;
}

मुझे क्रमबद्ध करने के लिए एक कॉलम निर्दिष्ट करने में सक्षम होना चाहिए ताकि यह पंक्तियों को पुनर्व्यवस्थित कर सके। कॉलम में से एक में Ymd H:i:s के प्रारूप में दिनांक जानकारी शामिल है Ymd H:i:s और मैं पहली पंक्ति होने वाली सबसे हाल की तारीख को सॉर्ट करने में सक्षम होना चाहता हूं।


बंद करने का उपयोग कर एकाधिक पंक्ति सॉर्टिंग

Uasort () और एक अनाम कॉलबैक फ़ंक्शन (बंद) का उपयोग करके एक और तरीका यहां दिया गया है। मैंने नियमित रूप से उस समारोह का उपयोग किया है। PHP 5.3 आवश्यक - कोई और निर्भरता नहीं!

/**
 * Sorting array of associative arrays - multiple row sorting using a closure.
 * See also: http://the-art-of-web.com/php/sortarray/
 *
 * @param array $data input-array
 * @param string|array $fields array-keys
 * @license Public Domain
 * @return array
 */
function sortArray( $data, $field ) {
    $field = (array) $field;
    uasort( $data, function($a, $b) use($field) {
        $retval = 0;
        foreach( $field as $fieldname ) {
            if( $retval == 0 ) $retval = strnatcmp( $a[$fieldname], $b[$fieldname] );
        }
        return $retval;
    } );
    return $data;
}

/* example */
$data = array(
    array( "firstname" => "Mary", "lastname" => "Johnson", "age" => 25 ),
    array( "firstname" => "Amanda", "lastname" => "Miller", "age" => 18 ),
    array( "firstname" => "James", "lastname" => "Brown", "age" => 31 ),
    array( "firstname" => "Patricia", "lastname" => "Williams", "age" => 7 ),
    array( "firstname" => "Michael", "lastname" => "Davis", "age" => 43 ),
    array( "firstname" => "Sarah", "lastname" => "Miller", "age" => 24 ),
    array( "firstname" => "Patrick", "lastname" => "Miller", "age" => 27 )
);

$data = sortArray( $data, 'age' );
$data = sortArray( $data, array( 'lastname', 'firstname' ) );

आप array_multisort() उपयोग कर सकते हैं

इस तरह कुछ कोशिश करें:

foreach ($mdarray as $key => $row) {
    // replace 0 with the field's index/key
    $dates[$key]  = $row[0];
}

array_multisort($dates, SORT_DESC, $mdarray);

PHP> = 5.5.0 के लिए बस क्रमबद्ध करने के लिए कॉलम निकालें। लूप की कोई ज़रूरत नहीं है:

array_multisort(array_column($mdarray, 0), SORT_DESC, $mdarray);

इससे पहले कि मैं टेबलस्टर कक्षा को चलाने के लिए प्राप्त कर सकूं, मैं शिनहान द्वारा प्रदान किए गए कार्यों के आधार पर एक समारोह के साथ आया था।

function sort2d_bycolumn($array, $column, $method, $has_header)
  {
  if ($has_header)  $header = array_shift($array);
  foreach ($array as $key => $row) {
    $narray[$key]  = $row[$column]; 
    }
  array_multisort($narray, $method, $array);
  if ($has_header) array_unshift($array, $header);
  return $array;
  }
  • $ सरणी एमडी ऐरे है जिसे आप सॉर्ट करना चाहते हैं।
  • $ कॉलम वह कॉलम है जिसे आप सॉर्ट करना चाहते हैं।
  • $ विधि यह है कि आप सॉर्ट प्रदर्शन कैसे करना चाहते हैं, जैसे SORT_DESC
  • $ has_header को सत्य पर सेट किया गया है यदि पहली पंक्ति में हेडर मान हैं जिन्हें आप सॉर्ट नहीं करना चाहते हैं।

मैं array_multisort का उपयोग करना पसंद करता हूं। here प्रलेखन देखें।


मैंने कई लोकप्रिय array_multisort () और usort () उत्तरों की कोशिश की और उनमें से कोई भी मेरे लिए काम नहीं किया। डेटा सिर्फ जुड़ा हुआ हो जाता है और कोड अपठनीय है। यहां एक त्वरित गंदा समाधान है। चेतावनी: अगर आप सुनिश्चित हैं कि एक बदमाश डिलीमीटर बाद में आपको पीछे हटने के लिए वापस नहीं आएगा तो केवल इसका इस्तेमाल करें!

आइए मान लें कि आपकी बहु सरणी में प्रत्येक पंक्ति इस तरह दिखती है: नाम, सामान 1, सामान 2:

// Sort by name, pull the other stuff along for the ride
foreach ($names_stuff as $name_stuff) {
    // To sort by stuff1, that would be first in the contatenation
    $sorted_names[] = $name_stuff[0] .','. name_stuff[1] .','. $name_stuff[2];
}
sort($sorted_names, SORT_STRING);

वर्णमाला क्रम में वापस अपनी सामग्री की आवश्यकता है?

foreach ($sorted_names as $sorted_name) {
    $name_stuff = explode(',',$sorted_name);
    // use your $name_stuff[0] 
    // use your $name_stuff[1] 
    // ... 
}

हाँ, यह गंदा है। लेकिन सुपर आसान, आपके सिर विस्फोट नहीं करेगा।


usort साथ। यहां एक सामान्य समाधान है, जिसे आप विभिन्न कॉलम के लिए उपयोग कर सकते हैं:

class TableSorter {
  protected $column;
  function __construct($column) {
    $this->column = $column;
  }
  function sort($table) {
    usort($table, array($this, 'compare'));
    return $table;
  }
  function compare($a, $b) {
    if ($a[$this->column] == $b[$this->column]) {
      return 0;
    }
    return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
  }
}

पहले कॉलम द्वारा सॉर्ट करने के लिए:

$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);





multidimensional-array