Sort Multi-dimensional array by decimal values - php

What I'm trying to do is sort a multi-dimensional array that contains decimal values. From what I've tested, floats are having trouble being ordered properly.
Array
(
[0] => Array
(
[company] => Ebay
[weight] => 4.6
)
[1] => Array
(
[company] => Ebay
[weight] => 1.7
)
[2] => Array
(
[company] => Ebay
[weight] => 3.7
)
)
usort($array, 'order_by_weight');
// Sorts DESC highest first
function order_by_weight($a, $b) {
return $b['weight'] - $a['weight'];
}
What is the best way to sort these numbers in descending?

$arr = array(
array('company' => 'A', 'weight' => 4.6),
array('company' => 'B', 'weight' => 1.7),
array('company' => 'C', 'weight' => 3.7),
);
usort($arr, 'order_by_weight');
function order_by_weight($a, $b) {
return $b['weight'] > $a['weight'] ? 1 : -1;
}
var_dump($arr);
PS: it's not a rocket science - this exact "trick" is used as the first example at http://php.net/usort

You can do this with anonymous function in just one line
$arr = array(
array('company' => 'A', 'weight' => 4.6),
array('company' => 'B', 'weight' => 1.7),
array('company' => 'C', 'weight' => 3.7),
);
usort($arr, function($a, $b) { return $b['weight'] > $a['weight'] ;});
print_r($arr);
Hope this helps :)

You can sort the array using array_multisort, altough, this is often used to sort on multiple array values instead of one.
echo "<pre>";
$a = array(
array('company' => 'ebay', 'weight' => 4.6),
array('company' => 'ebay', 'weight' => 1.7),
array('company' => 'ebay', 'weight' => 3.7),
array('company' => 'ebay', 'weight' => 2.7),
array('company' => 'ebay', 'weight' => 9.7),
array('company' => 'ebay', 'weight' => 0.7),
);
$company = array();
$weight = array();
foreach($a as $key=>$val) {
array_push($company, $val['company']);
array_push($weight, $val['weight']);
}
array_multisort($weight, SORT_ASC, $a);
print_r($a);

In case someone wants a more concise code, especially to handle equals condition you will add if condition before #zerkms's solution
using ceil will round fractions up and will sort the decimal numbers correctly
usort($data, function($a, $b)
{
return ceil($a[$_GET['sortby']] - $b[$_GET['sortby']]);
});

As sorting algo here is good example for sort multi dimension array without using any more inbuilt php function
$multiarr = array('0'=>array(
"hashtag" => "a7e87329b5eab8578f4f1098a152d6f4",
"title" => "Flower",
"order" => 3),
'1' => array(
'hashtag' => "b24ce0cd392a5b0b8dedc66c25213594",
"title" => "Free",
"order" => 2),
'2' => array('hashtag' => 'e7d31fc0602fb2ede144d18cdffd816b',
'title' => 'Ready',
'order' => 1
));
sorting function :
function multisort(&$array, $key) {
$valsort = array();
$ret = array();
reset($array);
foreach ($array as $ii => $va) {
$valsort[$ii] = $va[$key];
}
asort($valsort);
foreach ($valsort as $ii => $va) {
$ret[$ii] = $array[$ii];
}
$array = $ret;
}
multisort($multiarr, "order");
: output :
Array
(
[2] => Array
(
[hashtag] => e7d31fc0602fb2ede144d18cdffd816b
[title] => Ready
[order] => 1
)
[1] => Array
(
[hashtag] => b24ce0cd392a5b0b8dedc66c25213594
[title] => Free
[order] => 2
)
[0] => Array
(
[hashtag] => a7e87329b5eab8578f4f1098a152d6f4
[title] => Flower
[order] => 3
)
)

None of the earlier posted answers are demonstrating the most modern syntaxes for sorting by a column value.
If using usort(), use the three-way comparison operator ("spaceship operator ") from PHP7 and if you are on PHP7.4 or higher enjoy the brevity of "arrow function" syntax. For descending directional sorting write $b on the left of the operator and $a on the right. (Demo)
usort($arr, fn($a, $b) => $b['weight'] <=> $a['weight']);
array_multisort() can also be used, but it requires an additional loop to isolate a column of data. (Demo)
array_multisort(array_column($arr, 'weight'), SORT_DESC, $arr);

Related

Array to string conversion doing array_intersect [duplicate]

I have two arrays that both look like this:
Array
(
[0] => Array
(
[name] => STRING
[value] => STRING
)
[1] => Array
(
[name] => STRING
[value] => STRING
)
[2] => Array
(
[name] => STRING
[value] => STRING
)
)
and I would like to be able to replicate array_intersect by comparing the ID of the sub arrays within the two master arrays. So far, I haven't been successful in my attempts. :(
Use array_uintersect() to use a custom comparison function, like this:
$arr1 = array(
array('name' => 'asdfjkl;', 'value' => 'foo'),
array('name' => 'qwerty', 'value' => 'bar'),
array('name' => 'uiop', 'value' => 'baz'),
);
$arr2 = array(
array('name' => 'zxcv', 'value' => 'stuff'),
array('name' => 'asdfjkl;', 'value' => 'foo'),
array('name' => '12345', 'value' => 'junk'),
array('name' => 'uiop', 'value' => 'baz'),
);
$intersect = array_uintersect($arr1, $arr2, 'compareDeepValue');
print_r($intersect);
function compareDeepValue($val1, $val2)
{
return strcmp($val1['value'], $val2['value']);
}
which yields, as you would hope:
Array
(
[0] => Array
(
[name] => asdfjkl;
[value] => foo
)
[2] => Array
(
[name] => uiop
[value] => baz
)
)
function compareDeepValue($val1, $val2)
{
return strcmp($val1['value'], $val2['value']);
}
Be sure that val2 key is existing in val1 array, because the function is ordering array first. Very strange.
you can use embedded function with array_uintersect php function. ex:
$intersectNames = array_uintersect($arr1, $arr2, function ($val1, $val2){
return strcmp($val1['name'], $val2['name']);
});
$intersectValues = array_uintersect($arr1, $arr2, function ($val1, $val2){
return strcmp($val1['value'], $val2['value']);
});
print_r('namesIntersected' => $intersectNames, 'valuesIntersected' => $intersectValues)

Merge two arrays, replacing values of same key

I have two arrays
First Array
(
[0] => Array
(
[352] => 1
[128] =>
[64] =>
[70] => 2
)
)
Second array is like this :
Array
(
[0] => Array
(
[128] => 1.5
)
)
I want to make final array like this.(i want to store the matching into the main array in this example it is 128 -> 1.5) how can i do it.?
Array
(
[0] => Array
(
[352] => 1
[128] => 1.5
[64] =>
[70] => 2
)
)
here is my array variables:
print_r($listskilssresult);
print_r($listskilssresultmatching);
You need to use array_replace_recursive
$listskilssresult = [
[
352 => 1,
128 => '',
64 => '',
70 => 2
]
];
$listskilssresultmatching = [
[
128 => 1.5
]
];
print_r(array_replace_recursive($listskilssresult, $listskilssresultmatching));
Prints :
Array
(
[0] => Array
(
[352] => 1
[128] => 1.5
[64] =>
[70] => 2
)
)
Know the difference between array_replace_recursive and array_merge_recursive here
This is specific to your question. If you want to make something more automated, you can create a function. But this will do what you want:
<?php
$array1 = [[352 => 1, 128 => null, 64 => null, 70 => 2]];
$array2 = [[128 => 1.5]];
$keys1 = array_keys($array1[0]);
$keys2 = array_keys($array2[0]);
foreach ($keys1 as $key => $value) {
if (in_array($value, $keys2)) {
$array1[0][$value] = $array2[0][$value];
unset($array2[0][$value]);
}
}
if (!empty($array2[0])) {
foreach ($array2[0] as $key => $value) {
$array1[0][$key] = $value;
unset($array2[0][$key]);
}
}
print_r($array1[0]);
?>
The last if statement will add key + value from the 2nd array to the first if no match was found for them (from the foreach statement). You can just delete that condition if you just want to add only matching keys.
For this solution, you have to use array_merge() built-in php function.
Syntax:
$finalArray = array_merge($array1, $array2);
print_r($finalArray)
Example:
$array1 = array("color" => "red", 2, 4);
$array2 = array("a", "b", "color" => "green", "shape" => "trapezoid", 4);
$result = array_merge($array1, $array2);
print_r($result);
Output:
Array
(
[color] => green
[0] => 2
[1] => 4
[2] => a
[3] => b
[shape] => trapezoid
[4] => 4
)
Reference : http://php.net/manual/en/function.array-merge.php
array_replace_recursive is the best solution!
$old_array = Array('my_index1' => Array('1' => 'A', '2' => 'B'), 'my_index2' => Array('1' => 'C', '2' => 'D'));
$new_array = Array('my_index2' => Array('2' => 'Z'));
$result = array_replace_recursive($old_array, $new_array);
//Result : Array('my_index1' => Array('1' => 'A', '2' => 'B'), 'my_index2' => Array('1' => 'C', '2' => 'Z'));
array_merge would do the job for you:
array_merge($listskilssresult,$listskilssresultmatching)

Sort an array by value/key - mix of string and numeric values PHP

I need to sort an array. Both values and keys are the same and are strings. Basically, array looks similar to this:
$test = array(
'1' => '1',
'2' => '2',
'1.5' => '1.5',
'3' => '3',
'4' => '4',
'3.5' => '3.5',
'2XS' => '2XS',
'2XL' => '2XL',
'XXL' => 'XXL',
);
Expected Output:
Array
(
[0] => 1
[1] => 1.5
[2] => 2
[5] => 3
[6] => 3.5
[7] => 4
[3] => 2XL
[4] => 2XS
[8] => XXL
)
Any ideas?
PHP code demo
<?php
$test = array(
'1' => '1',
'2' => '2',
'1.5' => '1.5',
'3' => '3',
'4' => '4',
'3.5' => '3.5',
'2XS' => '2XS',
'2XL' => '2XL',
'XXL' => 'XXL',
);
$numericArray=array();
$stringsArray=array();
array_map(function($value) use (&$numericArray,&$stringsArray) {
if(is_numeric($value))
{
$numericArray[]=$value;//Here we are putting numeric values
}
else
{
$stringsArray[]=$value;//Here we are putting string values
}
}, $test);
sort($numericArray,SORT_NUMERIC);//sorting on numeric basis
sort($stringsArray,SORT_REGULAR);//sorting on string basis
$result=array_merge($numericArray,$stringsArray);//merging both of them
print_r($result);
Output:
Array
(
[0] => 1
[1] => 1.5
[2] => 2
[3] => 3
[4] => 3.5
[5] => 4
[6] => 2XL
[7] => 2XS
[8] => XXL
)
The solution using usort, is_numeric and strcmp functions:
usort($test, function ($a, $b) {
if (is_numeric($a) && is_numeric($b)) {
return $a - $b;
} else if (is_numeric($a) && !is_numeric($b)) {
return -1;
} else if (!is_numeric($a) && is_numeric($b)) {
return 1;
} else {
return strcmp($a, $b);
}
});
print_r($test);
The output:
Array
(
[0] => 1
[1] => 1.5
[2] => 2
[3] => 3
[4] => 3.5
[5] => 4
[6] => 2XL
[7] => 2XS
[8] => XXL
)
<?php
$test = array(
'1' => '1',
'2' => '2',
'1.5' => '1.5',
'3' => '3',
'4' => '4',
'3.5' => '3.5',
'2XS' => '2XS',
'2XL' => '2XL',
'XXL' => 'XXL',
);
function sortNandS($array){
$nums = [];
$strings = [];
foreach($array as $elm) {
is_numeric($elm) ? $nums[]= $elm : $strings[]=$elm;
}
sort($nums,SORT_NUMERIC);
sort($strings,SORT_REGULAR);
$result=array_merge($nums,$strings);
return $result;
}
print_r(sortNandS($test));
More efficiently than any previously posted answer, use array_multisort(). By passing an array of is_numeric() return values as the first parameter, your script will enjoy a lower time complexity because the is_numeric() calls will be n. Comparatively, usort() will be calling is_numeric() 2 * n log n (which is less efficient).
Code: (Demo)
array_multisort(
array_map('is_numeric', $test),
SORT_DESC,
$test
);
If you want to see what the usort() equivalent looks like: (Demo)
usort(
$test,
fn($a, $b) => [is_numeric($b), $a] <=> [is_numeric($a), $b]
);
Unlike uasort() and array_multisort(), usort() will re-index the array after modifying it.

How can I group by a count of a subvalue of an array?

I've been trying every combination of array_count_values and array_map I can think of. I'm hoping you can show me the way.
Here's a sample array:
$arr = array(
array('name' => 'foo','score' => 1),
array('name' => 'foo','score' => 2),
array('name' => 'bar','score' => 1)
);
I'd like to combine the scores of all sub values with the same name. Something like GROUP BY name in MySQL.
Array
(
[0] => Array
(
[name] => foo
[score] => 3
)
[1] => Array
(
[name] => bar
[score] => 1
)
)
I know there are other questions that sort multidimensional arrays, but I'm not able to find one that sums one of the sub values along the way.
You can use array_reduce
$arr = array(
array('name' => 'foo','score' => 1),
array('name' => 'foo','score' => 2),
array('name' => 'bar','score' => 1));
$array = array_reduce($arr, function ($a, $b) {
isset($a[$b['name']]['score']) ? $a[$b['name']]['score'] += $b['score'] : $a[$b['name']] = $b;
return $a;
});
var_dump($array);
Output
array
'foo' =>
array
'name' => string 'foo' (length=3)
'score' => int 3
'bar' =>
array
'name' => string 'bar' (length=3)
'score' => int 1

Using array_intersect on a multi-dimensional array

I have two arrays that both look like this:
Array
(
[0] => Array
(
[name] => STRING
[value] => STRING
)
[1] => Array
(
[name] => STRING
[value] => STRING
)
[2] => Array
(
[name] => STRING
[value] => STRING
)
)
and I would like to be able to replicate array_intersect by comparing the ID of the sub arrays within the two master arrays. So far, I haven't been successful in my attempts. :(
Use array_uintersect() to use a custom comparison function, like this:
$arr1 = array(
array('name' => 'asdfjkl;', 'value' => 'foo'),
array('name' => 'qwerty', 'value' => 'bar'),
array('name' => 'uiop', 'value' => 'baz'),
);
$arr2 = array(
array('name' => 'zxcv', 'value' => 'stuff'),
array('name' => 'asdfjkl;', 'value' => 'foo'),
array('name' => '12345', 'value' => 'junk'),
array('name' => 'uiop', 'value' => 'baz'),
);
$intersect = array_uintersect($arr1, $arr2, 'compareDeepValue');
print_r($intersect);
function compareDeepValue($val1, $val2)
{
return strcmp($val1['value'], $val2['value']);
}
which yields, as you would hope:
Array
(
[0] => Array
(
[name] => asdfjkl;
[value] => foo
)
[2] => Array
(
[name] => uiop
[value] => baz
)
)
function compareDeepValue($val1, $val2)
{
return strcmp($val1['value'], $val2['value']);
}
Be sure that val2 key is existing in val1 array, because the function is ordering array first. Very strange.
you can use embedded function with array_uintersect php function. ex:
$intersectNames = array_uintersect($arr1, $arr2, function ($val1, $val2){
return strcmp($val1['name'], $val2['name']);
});
$intersectValues = array_uintersect($arr1, $arr2, function ($val1, $val2){
return strcmp($val1['value'], $val2['value']);
});
print_r('namesIntersected' => $intersectNames, 'valuesIntersected' => $intersectValues)

Categories