कई कुंजियों द्वारा बहुआयामी सरणी को क्रमबद्ध करें


83

मैं कई कुंजियों द्वारा एक बहुआयामी सरणी को सॉर्ट करने की कोशिश कर रहा हूं, और मुझे पता नहीं है कि कहां शुरू करना है। मैंने उर्सॉर्ट को देखा, लेकिन यह निश्चित नहीं था कि मुझे क्या चाहिए के लिए एक फ़ंक्शन लिखना है।

मुझे राज्य द्वारा सॉर्ट करने की आवश्यकता है, फिर event_type, फिर तारीख।

मेरी सरणी इस तरह दिखती है:

    Array
(
    [0] => Array
        (
            [ID] => 1
            [title] => Boring Meeting
            [date_start] => 2010-07-30
            [time_start] => 06:45:PM
            [time_end] => 
            [state] => new-york
            [event_type] => meeting
        )

    [1] => Array
        (
            [ID] => 2
            [title] => Find My Stapler
            [date_start] => 2010-07-22
            [time_start] => 10:45:AM
            [time_end] => 
            [state] => new-york
            [event_type] => meeting
        )

    [2] => Array
        (
            [ID] => 3
            [title] => Mario Party
            [date_start] => 2010-07-22
            [time_start] => 02:30:PM
            [time_end] => 07:15:PM
            [state] => new-york
            [event_type] => party
        )

    [3] => Array
        (
            [ID] => 4
            [title] => Duct Tape Party
            [date_start] => 2010-07-28
            [time_start] => 01:00:PM
            [time_end] => 
            [state] => california
            [event_type] => party
        )
...... etc

1
... और आप इसे कैसे छाँटना चाहते हैं?
धोखा

जवाबों:


185

आप की जरूरत है array_multisort

$mylist = array(
    array('ID' => 1, 'title' => 'Boring Meeting', 'event_type' => 'meeting'),
    array('ID' => 2, 'title' => 'Find My Stapler', 'event_type' => 'meeting'),
    array('ID' => 3, 'title' => 'Mario Party', 'event_type' => 'party'),
    array('ID' => 4, 'title' => 'Duct Tape Party', 'event_type' => 'party')
);

# get a list of sort columns and their data to pass to array_multisort
$sort = array();
foreach($mylist as $k=>$v) {
    $sort['title'][$k] = $v['title'];
    $sort['event_type'][$k] = $v['event_type'];
}
# sort by event_type desc and then title asc
array_multisort($sort['event_type'], SORT_DESC, $sort['title'], SORT_ASC,$mylist);

PHP 5.5.0 के रूप में:

array_multisort(array_column($mylist, 'event_type'), SORT_DESC,
                array_column($mylist, 'title'),      SORT_ASC,
                $mylist);

$mylist अब है:

array (
  0 => 
  array (
    'ID' => 4,
    'title' => 'Duct Tape Party',
    'event_type' => 'party',
  ),
  1 => 
  array (
    'ID' => 3,
    'title' => 'Mario Party',
    'event_type' => 'party',
  ),
  2 => 
  array (
    'ID' => 1,
    'title' => 'Boring Meeting',
    'event_type' => 'meeting',
  ),
  3 => 
  array (
    'ID' => 2,
    'title' => 'Find My Stapler',
    'event_type' => 'meeting',
  ),
)

@ रब मैं बहुत उत्सुक हूं कि आप
दिनांक_start को

6
"डक्ट टेप पार्टी" क्या है?
gdaniel

PHP <5.5 के लिए array_columnफ़ंक्शन github.com/ramsey/array_column के लिए पॉलीफ़िल है । इसलिए विरासत संस्करणों पर दूसरे कोड स्निपेट से अधिक सुरुचिपूर्ण तरीके का उपयोग करना संभव है।
userlond

15

आप इसके साथ कर सकते हैं usort$cmp_functionतर्क हो सकता है:

function my_sorter($a, $b) {
    $c = strcmp($a['state'], $b['state']);
    if($c != 0) {
        return $c;
    }

    $c = strcmp($a['event_type'], $b['event_type']);
    if($c != 0) {
        return $c;
    }

    return strcmp($a['date_start'], $b['date_start']);
}

PHP 5.3 में फ़ील्ड की एक मनमानी संख्या के लिए, आप तुलना फ़ंक्शन बनाने के लिए क्लोजर का उपयोग कर सकते हैं:

function make_cmp($fields, $fieldcmp='strcmp') {
    return function ($a, $b) use (&$fields) {
        foreach ($fields as $field) {
            $diff = $fieldcmp($a[$field], $b[$field]);
            if($diff != 0) {
                return $diff;
            }
        }
        return 0;
    }
}

usort($arr, make_cmp(array('state', 'event_type', 'date_start')))

PHP 5.3 में विभिन्न प्रकार के क्षेत्रों की एक मनमानी संख्या के लिए:

function make_cmp($fields, $dfltcmp='strcmp') {
    # assign array in case $fields has no elements
    $fieldcmps = array();
    # assign a comparison function to fields that aren't given one
    foreach ($fields as $field => $cmp) {
        if (is_int($field) && ! is_callable($cmp)) {
            $field = $cmp;
            $cmp = $dfltcmp;
        }
        $fieldcmps[$field] = $cmp;
    }
    return function ($a, $b) use (&$fieldcmps) {
        foreach ($fieldcmps as $field => $cmp) {
            $diff = call_user_func($cmp, $a[$field], $b[$field]);
            if($diff != 0) {
                return $diff;
            }
        }
        return 0;
    }
}

function numcmp($a, $b) {
    return $a - $b;
}
function datecmp($a, $b) {
    return strtotime($a) - strtotime($b);
}
/**
 * Higher priority come first; a priority of 2 comes before 1.
 */
function make_evt_prio_cmp($priorities, $default_priority) {
    return function($a, $b) use (&$priorities) {
        if (isset($priorities[$a])) {
            $prio_a = $priorities[$a];
        } else {
            $prio_a = $default_priority;
        }
        if (isset($priorities[$b])) {
            $prio_b = $priorities[$b];
        } else {
            $prio_b = $default_priority;
        }
        return $prio_b - $prio_a;
    };
}

$event_priority_cmp = make_evt_prio_cmp(
    array('meeting' => 5, 'party' => 10, 'concert' => 7), 
    0);

usort($arr, make_cmp(array('state', 'event' => $event_priority_cmp, 'date_start' => 'datecmp', 'id' => 'numcmp')))

1
आप घोंसले के शिकार को थोड़ा सरल कर सकते हैं, और मुझे लगता है कि आपको तारीख के साथ कुछ और करने की आवश्यकता होगी, लेकिन दृष्टिकोण अभी तक सबसे अच्छा लगता है।
deceze

1
नमूना सरणी में उपयोग किए जाने वाले '% Y-% m-% d' प्रारूप के बारे में अच्छी बात यह है कि तारीख तुलना के लिए स्ट्रिंग तुलनात्मक कार्य है।
1

11

PHP7 कई कॉलमों द्वारा छंटनी करता है, जो स्पेसशिप ऑपरेटर ( <=>) "कंबाइंड कम्पेरिज़न ऑपरेटर" या "थ्री-वे कम्पेरिजन ऑपरेटर" के साथ आसान है।

संसाधन: https://wiki.php.net/rfc/combined-comparison-operator

कई कॉलमों को छांटना उतना ही सरल है जितना कि ऑपरेटर के दोनों ओर संतुलित / संबंधपरक सरणियाँ लिखना। आराम से किया!

मैंने उपयोग नहीं किया है uasort()क्योंकि मुझे मूल अनुक्रमों को संरक्षित करने की कोई आवश्यकता नहीं है।

कोड: ( डेमो )

$array = [
    ['ID' => 1, 'title' => 'Boring Meeting', 'date_start' => '2010-07-30', 'event_type' => 'meeting', 'state' => 'new-york'],
    ['ID' => 2, 'title' => 'Find My Stapler', 'date_start' => '2010-07-22', 'event_type' => 'meeting', 'state' => 'new-york'],
    ['ID' => 3, 'title' => 'Mario Party', 'date_start' => '2010-07-22', 'event_type' => 'party', 'state' => 'new-york'],
    ['ID' => 4, 'title' => 'Duct Tape Party', 'date_start' => '2010-07-28', 'event_type' => 'party', 'state' => 'california']
];

usort($array, function($a, $b) {
    return [$a['state'], $a['event_type'], $a['date_start']]
           <=>
           [$b['state'], $b['event_type'], $b['date_start']];
});

var_export($array);

उत्पादन

array (
  0 => 
  array (
    'ID' => 4,
    'title' => 'Duct Tape Party',
    'date_start' => '2010-07-28',
    'event_type' => 'party',
    'state' => 'california',
  ),
  1 => 
  array (
    'ID' => 2,
    'title' => 'Find My Stapler',
    'date_start' => '2010-07-22',
    'event_type' => 'meeting',
    'state' => 'new-york',
  ),
  2 => 
  array (
    'ID' => 1,
    'title' => 'Boring Meeting',
    'date_start' => '2010-07-30',
    'event_type' => 'meeting',
    'state' => 'new-york',
  ),
  3 => 
  array (
    'ID' => 3,
    'title' => 'Mario Party',
    'date_start' => '2010-07-22',
    'event_type' => 'party',
    'state' => 'new-york',
  ),
)

पीएस 7 तीर PHP7.4 और उच्चतर ( डेमो ) के साथ सिंटैक्स ...

usort($array, fn($a, $b) =>
    [$a['state'], $a['event_type'], $a['date_start']]
    <=>
    [$b['state'], $b['event_type'], $b['date_start']]
);

हर छँटाई मानदंडों array_multisort()के array_column()लिए समकक्ष तकनीक और एक कॉल है: ( डेमो )

array_multisort(
    array_column($array, 'state'),
    array_column($array, 'event_type'),
    array_column($array, 'date_start'),
    $array
);

2
class Sort {
    private $actual_order = 'asc';
    private $actual_field = null;

    public function compare_arrays($array1, $array2) {

        if ($array1[$this->actual_field] == $array2[$this->actual_field]) {
            return 0;
        }
        elseif ($array1[$this->actual_field] > $array2[$this->actual_field]) {
            return ($this->actual_order == 'asc' ? 1 : -1);
        }
        else {
            return ($this->actual_order == 'asc' ? -1 : 1);
        }

    }


    public function order_array(&$array) {

        usort($array, array($this, 'compare_arrays'));

    }


    public function __construct ($field, $actual_order = 'asc') {
        $this->actual_field = $field;
        $this->actual_order = $actual_order;
    }

}

// use

$sort = new Sort ("state");

$sort->order_array($array);

यह उत्तर इसकी शैक्षिक व्याख्या को याद कर रहा है। तीन स्तंभों पर एक बहुआयामी सरणी को सॉर्ट करने के बारे में यह उत्तर ओपी के प्रश्न को कैसे हल करता है?
मिकमैकुसा

2

मैंने कोड को नीचे करने की कोशिश की है और मैंने सफलतापूर्वक

सरणी कोड

$songs =  array(
        '1' => array('artist'=>'Smashing Pumpkins', 'songname'=>'Soma'),
        '2' => array('artist'=>'The Decemberists', 'songname'=>'The Island'),
        '3' => array('artist'=>'Fleetwood Mac', 'songname' =>'Second-hand News')
);

कॉल सरणी छँटाई समारोह

$songs = subval_sort($songs,'artist'); 
print_r($songs);

सरणी की छंटाई

function subval_sort($a,$subkey) {
    foreach($a as $k=>$v) {
        $b[$k] = strtolower($v[$subkey]);
    }
    asort($b);
    foreach($b as $key=>$val) {
        $c[] = $a[$key];
    }
    return $c;
}

यदि सरणी रिवर्स सॉर्टिंग फ़ंक्शन

function subval_sort($a,$subkey) {
        foreach($a as $k=>$v) {
            $b[$k] = strtolower($v[$subkey]);
        }
        arsort($b);
        foreach($b as $key=>$val) {
            $c[] = $a[$key];
        }
        return $c;
    }

यह केवल कॉलम (एक अयोग्य तरीके से) के अनुसार होता है, लेकिन ओपी के प्रश्न में तीन कॉलम मानों को शामिल करने के लिए छंटाई के मापदंड की आवश्यकता होती है। सबसे अच्छा, यह एक अलग प्रश्न का सही उत्तर है।
मिकमैकुसा

2

@Stijn Leenknegt के जीनियस कोड में सुधार, यहां मेरा 2 प्रतिशत व्यावहारिक कार्य है:

$data[] = array('volume' => 67, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 1);
$data[] = array('volume' => 85, 'edition' => 6);
$data[] = array('volume' => 98, 'edition' => 2);
$data[] = array('volume' => 86, 'edition' => 6);
$data[] = array('volume' => 67, 'edition' => 7);

function make_cmp(array $sortValues)
{
    return function ($a, $b) use (&$sortValues) {
        foreach ($sortValues as $column => $sortDir) {
            $diff = strcmp($a[$column], $b[$column]);
            if ($diff !== 0) {
                if ('asc' === $sortDir) {
                    return $diff;
                }
                return $diff * -1;
            }
        }
        return 0;
    };
}

usort($data, make_cmp(['volume' => "desc", 'edition' => "asc"]));

if ($diff) { return $diff * ($sortDir === 'asc' ? 1 : -1); }
मिकमैकुसा

0

शायद यह किसी की मदद करता है:

// data to sort
$output = array(
        array('ID' => 1, 'title' => 'Boring Meeting', 'event_type' => 'meeting'),
        array('ID' => 2, 'title' => 'Find My Stapler', 'event_type' => 'meeting'),
        array('ID' => 3, 'title' => 'Mario Party', 'event_type' => 'party'),
        array('ID' => 4, 'title' => 'Duct Tape Party', 'event_type' => 'party')
);

// multi column, multi direction order by
$body['order_by'] = array(
        array("field"=> "event_type", "order"=> "desc"),
        array("field"=> "title", "order"=> "asc"),
        array("field"=> "ID", "order"=> "asc"),
);

$output = $this->multiColumnMultiDirectionSort($body, $output);


public function multiColumnMultiDirectionSort(array $body, array $output)
{
    // get order fields and its direction in proper format
    $orderFieldDirection = [];
    if (!empty($body['order_by']) && is_array($body['order_by'])) {
        foreach ($body['order_by'] as $order) {
            $orderDirection = $order['order'] == "desc" ? SORT_DESC : SORT_ASC; // we need format that array_multisort supports
            $orderFieldDirection[$order['field']] = $orderDirection;
        }
    }

    if (!empty($orderFieldDirection)) {
        // get the list of sort columns and their data in the format that is required by array_multisort
        $amParams = [];
        $sort = [];
        foreach ($orderFieldDirection as $field => $order) {
            foreach ($output as $k => $v) {
                $sort[$field][$k] = $v[$field];
            }

            $amParams[] = $sort[$field];
            $amParams[] = $order;
            $amParams[] = SORT_REGULAR; // this is not needed, but we can keep as it might come handy in the future
        }

        $amParams[] = &$output; // very important to pass as reference
        call_user_func_array("array_multisort", $amParams);
    }

    return $output;
}

-1

यदि आप मल्टी डाइमेंशनल सरणी को सॉर्ट करना चाहते हैं

पहला सरणी है:

$results['total_quote_sales_person_wise']['quote_po'];

दूसरा है:

$results['total_quote_sales_person_wise']['quote_count'];

यह दोनों बहु-विषयक सरणी आप एक समय में अवरोही क्रम को क्रमबद्ध करना चाहते हैं तो इस कोड का उपयोग करें:

array_multisort($results['total_quote_sales_person_wise']['quote_po'],SORT_DESC, $results['total_quote_sales_person_wise']['quote_count'],SORT_DESC);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.