PHP: Sorting Multi-Array Result [duplicate] - php

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I sort a multidimensional array in php
Array ( [0] => Array (
[card_name] => CardA
[str] => 10
[def] => 10
[desc] => - Recover 150 points of vitality
- Attack twice"
[qty] => 5
)
[1] => Array (
[card_name] => CardD
[str] => 40
[def] => 40
[desc] => - Investigate enemy's weakpoint
[qty] => 3
)
[2] => Array ( [card_name] => CardG
[str] => 35
[def] => 20
[desc] =>
[qty] => 1
)
[3] => Array (
[card_name] => CardH
[str] => 25
[def] => 30
[desc] =>
[qty] => 1
)
[4] => Array (
[card_name] => CardI
[str] => 15
[def] => 40
[desc] => - Enhance strength
[qty] => 1
)
[5] => Array (
[card_name] => CardJ
[str] => 5
[def] => 50
[desc] => - Make silence
[qty] => 3
)
)
I have a simple question about sorting arrays. I just want to sort the array in either by str or def in either asc or desc. The examples in the php.net is a bit confusing and I was wondering if anyone can solve this small dilemma.
I know I should be using array_multi_sort for this.
Thanks.

Use the usort function. It will be something like this in your case :
function compare($valueA, $valueB) {
if ($valueA['str'] > $valueb['str']) {
return 1;
} else if ($valueA['str'] < $valueb['str']) {
return -1;
}
return 0;
}
usort($yourArray, "compare");

Try php usort - http://www.php.net/manual/en/function.usort.php
I've not tried and run the code but it'll be something below:
function cmp($a, $b)
{
return strcmp($a['def'],$b['def'])
}
$a = yourArray[];
usort($a, "cmp");
This will iterate through each element and pass the array element as a parameter and will use your custom function to sort.

usort() and strnatcmp() is your solution:
<?php
function build_sorter($key) {
return function ($a, $b) use ($key) {
return strnatcmp($a[$key], $b[$key]);
};
}
usort($array, build_sorter('def'));
print_r($array);
?>
It will sort all arrays by your defined key.

Array multisort requires you to build an array holding the values of the keys you want to sort by to do what you want, but with the same first dimension keys of the original array.
Thus if you make an array which holds 0 => 10, 1 => 5... etc where those are the values for str or def for keys 0 and 1, then you can do
foreach($originalArray as $key => $record) {
$keyValuesArray[$key] = $record['str'];
}
array_multisort($keyvaluesArray, SORT_ASC, $originalArray);
And original array would be modified to be sorted.
As for what you should be doing, I don't think array multisort is "the way" to do it, but is not a terrible way of doing it. Other solutions might be slightly more efficient.

Related

How to sort multidimensional array by name/timestamp? [duplicate]

This question already has answers here:
How can I sort arrays and data in PHP?
(14 answers)
Closed 5 years ago.
I were using the "rsort" function to sort through the timestamps when the array only contained a timestamp and were not multidimensional.
So now the question is how do i approach this?
The array looks something similair to this
Array
(
[0] => Array
(
[type] => post
[id] => 1
[timestamp] => 2017-08-12 21:03:22
[poster] => 1
[profile] => 1
[post] => Testtttttinngggs
)
[1] => Array
(
[type] => post
[id] => 2
[timestamp] => 2017-08-12 21:03:18
[poster] => 1
[profile] => 5
[post] => Hello you
)
[2] => Array
(
[type] => post
[id] => 3
[timestamp] => 2017-08-12 21:03:33
[poster] => 1
[profile] => 1
[post] => Somesay timestamp is screwed
)
[3] => Array
(
[type] => post
[id] => 4
[timestamp] => 2017-08-12 21:28:54
[poster] => 1
[profile] => 1
[post] => This is truely a teeest
)
[4] => Array
(
[type] => post
[id] => 5
[timestamp] => 2017-08-13 15:04:34
[poster] => 1
[profile] => 1
[post] => Test test test test
)
)
You can use array_multisort
array_multisort(array_column($list, 'timestamp'), SORT_ASC, $list);
You can use usort
usort($array, function($a, $b)
{
if($a['timestamp']>$b['timestamp'])
{
return -1;
}
elseif($a['timestamp']<$b['timestamp'])
{
return 1;
}
return 0;
});
Update
I was wrong. Axalix' answer runs a lot faster than mine and Rob Ruchte's. My tests:
$data = [
['timestamp'=> '2015-08-12', 'id'=>1],
['timestamp'=> '2017-07-13', 'id'=>2],
['timestamp'=> '2017-01-12', 'id'=>3],
];
function useUsort($data){
usort($data,function($a,$b) {
return strtotime($b['timestamp']) - strtotime($a['timestamp']);
});
};
function useMultisort($data){
array_multisort(array_column($data, 'timestamp'), SORT_DESC, $data);
};
$start = microtime(true);
for($i=1;$i<=100000;$i++) useUsort($data);
$t1 = microtime(true);
for($i=1;$i<=100000;$i++) useMultisort($data);
$t2 = microtime(true);
echo "usort: ". round(($t1 - $start) * 1000) . " ms\n";
echo "array_multisort: ". round(($t2 - $t1) * 1000) . " ms\n";
My result:
usort: 2262 ms
array_multisort: 246 ms
Original answer
#Axalix' answer is nice but I would take a different approach. Because you only care about sorting by one field (timestamp), array_multisort is overkill as it was design to sort by multiple fields. I would do:
usort($data,function($a,$b) {
return strtotime($b['timestamp']) - strtotime($a['timestamp']);
});
Live demo
This will easily outperform array_multisort because it doesn't require PHP to first extract the timestamp into a separate column array, and then execute the multisort (a more complex function than my simple comparator function) on it.

How to sort associative array?

I have associative array. On print_f($array_name), I got this
Array (
[0] => Array (
[teamid] => abc
[distance] => 1.25
)
[1] => Array (
[teamid] => xyz
[distance] => 0.25
)
)
This is that array which I want to sort according to distance. eg, This should be look like this after sorting,
Array (
[0] => Array (
[teamid] => xyz
[distance] => 0.25
)
[1] => Array (
[teamid] => abc
[distance] => 1.25
)
)
If anyone know answer then please explain or suggest me link from where I can understand from beginning. Thank You.
Here is what you need to do.
$a = array(array( 'teamid' => 'abc', 'distance' => 1.25 ), array( 'teamid' => 'xyz', 'distance' => 0.25 ));
$distance = array();
foreach ($a as $key => $row)
{
$distance[$key] = $row['distance'];
}
array_multisort($distance, SORT_ASC, $a);
print_r($a);
This outputs
Array
(
[0] => Array
(
[teamid] => xyz
[distance] => 0.25
)
[1] => Array
(
[teamid] => abc
[distance] => 1.25
)
)
source Example #3 Sorting database results
DEMO
Edit
as per Mike's comment,
here are two answers,
one tells that on single array you should use usort(as Mike's answer) and array_multisort is used to compare elements from different arrays (or sub-arrays) at the same time.
in the other answer, as Mike wants some bench marking
usort() is more concise and doesn't require extracting a column array to feed to array_multisort(). (It also does less than array_multisort.)
However, when I repeatedly tested it today on arrays of 20,000 and
10,000 representative data rows, usort() was 7-15x slower than
array_multisort() when the column was random values of type int and
the column was pre-extracted. That is as one might expect, since for
every comparison you're comparing an entire php function call to
optimized intrinsic code.
more about bench marking notes, read full answer
$array = array(
array('teamid' => 'a', 'distance' => 1.25),
array('teamid' => 'b', 'distance' => 0.25),
array('teamid' => 'c', 'distance' => 2.5),
array('teamid' => 'd', 'distance' => 0.75),
);
function cmp($a, $b)
{
if ($a['distance'] == $b['distance']) return 0;
return ($a['distance'] < $b['distance']) ? -1 : 1;
}
usort($array, "cmp");
More info: http://php.net/usort

Sorting multidimensial array by two values containing numbers and letters

I have an array which looks like
[0] => Array
(
[typeName] => Element
[quantity] => 35
[flag] => 4
)
I already found a way by using usort() to sort an array by its sub elements. Which works great for numeric values.
public static function _sortByAmount($a, $b) {
return $b['quantity'] - $a['quantity'];
}
From time to time, it could happen that I have more than one array elements with the same quantity. Those entries should be sorted by the Name too. In the end, the array should look like this.
[0] => Array
(
[typeName] => Element
[quantity] => 567
[flag] => 4
)
[1] => Array
(
[typeName] => aaa-element
[quantity] => 35
[flag] => 4
)
[2] => Array
(
[typeName] => bbb-element
[quantity] => 35
[flag] => 4
)
[3] => Array
(
[typeName] => Element
[quantity] => 10
[flag] => 4
)
Is it possible to extend my function somehow?
You can check anything you want in your compare function. For example, if quantity == quantity then return strcmp.
public static function _sortByAmount($a, $b) {
if($b['quantity'] == $a['quantity']){
return strcmp($a['typeName'], $b['typeName']);
} else {
return $b['quantity'] - $a['quantity'];
}
}
you can also use strcasecmp if you want the check to be case insensitive.
not sure, but
public static function _sortByAmount($a, $b) {
$byQuantity = $a['quantity'] - $b['quantity'];
return $byQuantity ?: strcmp($a['typeName'], $b['typeName']);
}

Reducing multidimensional array

I have the following multidimensional array:
Array
(
[0] => Array
(
[area] => 5
[estante] => 5
[anaquel] => 5
[no_caja] => 5
[id_tipo] => 3
[nombre_tipo] => Administrativo
)
[1] => Array
(
[area] => 5
[estante] => 5
[anaquel] => 5
[no_caja] => 5
[id_tipo] => 1
[nombre_tipo] => Copiador
)
[2] => Array
(
[area] => 5
[estante] => 5
[anaquel] => 5
[no_caja] => 5
[id_tipo] => 2
[nombre_tipo] => Judicial
)
)
and I want to reduce it by having all the different values (intersection) between them. The dimension of the array may change (I'm retrieving the info from a database). I have thought in using functions like array_reduce and array_intersect, but I have the problem that they work only with one-dimension arrays and I can't find the way to pass an indefinite (not previous known) number of parameters to these function. I'd like to have an output like this:
Array([0]=>Copiador, [1]=>Administrativo, [2]=>Judicial).
How can I do this?
Thanks in advance.
$arr=array(
array (
'area' => 5 ,
'estante' => 5 ,
'anaquel' => 5,
'no_caja' => 5,
'id_tipo' => 3,
'nombre_tipo' => 'Administrativo'),
array (//etc.
)
);
$fn=function(array $a, $k){
if(array_key_exists($k,$a)) return $a[$k];
};
$b=array_map($fn,$arr,array_fill(0,count($arr),'nombre_tipo'));
print_r($b);
/*
Array
(
[0] => Administrativo
[1] => Copiador
[2] => Judicial
)
*/
$reduced = array();
foreach ($oldarray as $value) {
$reduced[] = $value['nombre_tipo'];
}
Although, a better solution may be to just modify your SQL query so you get the correct data to begin with.
Note: you can also do it with array_reduce, but I personally prefer the method above.
$reduced = array_reduce($oldarray,
function($a, $b) { $a[] = $b['nombre_tipo']; return $a; },
array()
);
This task is exactly what array_column() is for -- extracting columnar data.
Call this:
var_export(array_column($your_array, 'nombre_tipo'));
This will output your desired three-element array. ...I don't understand the sorting in your desired output.
Seems like you want array_map
$newArr = array_map(function($a) {
return $a['nombre_tipo'];
}, $oldArr);
var_dump($newArr);

How can I tell if the value of any array key is the value I'm looking for?

I have an array of arrays like this:
$cart = Array (
[0] => Array ( [TypeFlag] => S [qty] => 2 [denom] => 50 [totalPrice] => 100 )
[1] => Array ( [TypeFlag] => V [qty] => 1 [denom] => 25 [totalPrice] => 25 )
[2] => Array ( [TypeFlag] => C [qty] => 1 [denom] => 25 [totalPrice] => 25 )
)
Is there any way, short of looping through all of them and checking one at a time, to determine if the TypeFlag value for any of them is S?
Try this:
foreach($cart as $key => $value) {
if ($value['TypeFlag'] == 'S') {
return $key;
}
}
This would return the key of the sub-array that has a TypeFlag value of S. However, this would stop after it finds the first sub-array that matches your search pattern. Not sure what your desired output is tho and how many results are expected. If you can provide more info, I can give you a more accurate example.
Given a function that returns the TypeFlag for each element of your array:
function get_type_flag($item) {
return $item["TypeFlag"];
}
You could apply that function to each element in the array:
$typeflags = array_map("get_type_flag", $cart);
and see if S is in that array:
if (in_array("S", $typeflags)) {
...
}

Categories