Sort a multidimensional array by two variables - php

I have an array that looks something like below, but it could potentially contain more drafts.
$multi_arr = array(
'draft1' => array (
'alloc_coeff' => 560,
'steps_count' => 2,
'order_draft' => array(
'0' => array(
'whse_id' => 4,
'quantity' => 0,
'percent' => 0
),
'1' => array(
'whse_id' => 1,
'quantity' => 10,
'percent' => 66.666666666667
)
)
),
'draft2' => array (
'alloc_coeff' => 1517,
'steps_count' => 1,
'order_draft' => array(
'0' => array(
'whse_id' => 1,
'quantity' => 10,
'percent' => 66.666666666667
)
)
),
'draft3' => array (
'alloc_coeff' => 559,
'steps_count' => 2,
'order_draft' => array(
'0' => array(
'whse_id' => 2,
'quantity' => 0,
'percent' => 0
),
'1' => array(
'whse_id' => 1,
'quantity' => 10,
'percent' => 66.666666666667
)
)
)
);
I need to sort the content by using two variables: alloc_coeff and steps_count.
First alloc_coeff needs to be considered from the highest to the lowest value.
And then as a second variable the steps_count from lowest value to highest.
usort($multi_arr, function($a, $b) {
return $a['alloc_coeff'] <=> $b['alloc_coeff'];
});
I don't need the entire array to be rewritten and stored in a temporary variable, I just need the keys sorted like this (expected outcome) draft2, draft1 and lastly draft3.
What's a way to accomplish this?

You can do it like below:-
array_multisort(array_column($multi_arr, 'alloc_coeff'), SORT_DESC,
array_column($multi_arr, 'steps_count'), SORT_ASC,
$multi_arr);
Output:- https://eval.in/924894 And https://eval.in/924892
Note:- tested in 5.6.23 and PHP 7.0.8

Related

php usort() with order of precedence for json sorting

I need to sort a json array with key value pair in a certain order of precedence(specialcharacters > numbers > lower case > uppercase). I tried with ascii code but couldn't get as expected.
$arr1 = array (
0 =>
array (
'id' => 1,
'name' => 'B',
'value' => 'abc',
'order' => 6,
),
1 =>
array (
'id' => 2,
'name' => 'a',
'value' => 'xyz',
'order' => 2,
),
2 =>
array (
'id' => 3,
'name' => 'A',
'value' => 'ghi',
'order' => 1,
),
3 =>
array (
'id' => 4,
'name' => '123',
'value' => 'xyz',
'order' => 2,
),
4 =>
array (
'id' => 5,
'name' => 'd',
'value' => 'uvw',
'order' => 3,
),
5 =>
array (
'id' => 6,
'name' => '#2',
'value' => 'def',
'order' => 3,
),
);
function cmp($a, $b)
{
$at = iconv('UTF-8', 'ASCII//TRANSLIT', $a['name']);
$bt = iconv('UTF-8', 'ASCII//TRANSLIT', $b['name']);
return strcmp($at, $bt);
}
usort($arr1, "cmp");
print_r($arr1);
Can anyone help me to resolve it?
<?php
// Obtain a list of columns
foreach ($arr1 as $key => $row) {
$arr1[$key] = $row['value'];
}
ksort($arr1);
?>

How to access this array

array (
'_attributes' =>
array (
'name' => 'Rothco Product API - Variations',
),
'item_variations' =>
array (
0 =>
stdclass::__set_state(array(
'item_variation_id' => 2,
'item_index' => 3146,
'rothco_item_no' => '10002',
'upc' => '023063601212',
'inventory' => 99,
'created_date' => '2014-11-28 10:06:45.000',
'weight' => '.4000',
'image_filename' => '10002-A.jpg',
'catalog_page_no' => 183,
'msrp' => '20.9900',
'map' => '.0000',
'diameter' => '',
'price' => '8.100000',
'case_price' => NULL,
'case_quantity' => NULL,
'statuses' => '',
)),
),
)
This is my array $list.
I want to access 'item_variations' value from this array,
but if I try $list['item_variations'], or $list->['item_variations']
it is not working
If you want to reach just item_variations then
echo $list['item_variations'];
is sufficient. Things get more tricky if you would like to i.e. get value if created_date from your sample data as you got mix of arrays and objects so that require different access:
echo $list['item_variations'][0]->created_date;
which would output
2014-11-28 10:06:45.000

Change the value of a key inside stdClass::__set_state(array(

I have the following returned array (results from a var_export())
array (
0 =>
stdClass::__set_state(array(
'term_id' => 145,
'name' => 'testing',
'slug' => 'testing',
'term_group' => 0,
'term_taxonomy_id' => 145,
'taxonomy' => 'post_tag',
'description' => '',
'parent' => 0,
'count' => 2,
'filter' => 'raw',
)),
)
I need to change the value of $output[0]->count to a new value. I can unset the key/value pair successfully with unset($output[0]->count), but I just can't seem to set a new key/value pair.
I have tried using
$count['count'] = count( $list_term );
$result = array_merge_recursive($output, $count);
but then I get the following output
array (
0 =>
stdClass::__set_state(array(
'term_id' => 145,
'name' => 'testing',
'slug' => 'testing',
'term_group' => 0,
'term_taxonomy_id' => 145,
'taxonomy' => 'post_tag',
'description' => '',
'parent' => 0,
'filter' => 'raw',
)),
'count' => 5,
)
If I try with
$result = array_merge_recursive($output[0], $count);
I get the following error
WARNING Error: [2] array_merge_recursive(): Argument #1 is not an array
Any suggestions on how to solve this
Just cast your object to an array
$result = array_merge_recursive((array)$output[0], $count);

PHP - structure multidimensional array depending on values

I have an array:
$initialarray = array(
0 = array(
'unit' => 1,
'class' => 1,
'value' => 'string1'
),
1 = array(
'unit' => 1,
'class' => 2,
'value' => 'string2'
),
2 = array(
'unit' => 1,
'class' => 2,
'value' => 'string3'
),
3 = array(
'unit' => 2,
'class' => 1,
'value' => 'string4'
)
4 = array(
'unit' => 2,
'class' => 2,
'value' => 'string5'
)
);
What would be the best way to structure it (to group the resulting sub-arrays) depending first on the 'unit' field's values, and then depending on the 'class' field's values, like so:
$resultarray = array(
// array of all the sub-arrays of 'unit' = 1
$unit[1] = array(
// array of all the sub-arrays of 'unit' = 1 and 'class' = 1
$class[1] = array(
0 = array(
'unit' => 1,
'class' => 1,
'value' => 'string1'
)
)
// array of all the sub-arrays of 'unit' = 1 and 'class' = 2
$class[2] = array(
0 = array(
'unit' => 1,
'class' => 2,
'value' => 'string2'
),
1 = array(
'unit' => 1,
'class' => 2,
'value' => 'string3'
)
)
)
// array of all the sub-arrays of 'unit' = 2
$unit[2] = array(
// array of all the sub-arrays of 'unit' = 2 and 'class' = 1
$class[1] = array(
0 = array(
'unit' => 2,
'class' => 1,
'value' => 'string4'
)
)
// array of all the sub-arrays of 'unit' = 2 and 'class' = 2
$class[2] = array(
0 = array(
'unit' => 2,
'class' => 2,
'value' => 'string5'
)
)
)
)
I have asked a similar question here and got a working answer for only one iteration, i.e. for only structuring the array by one of the fields. But I could not make the same solution work for multiple iterations, i.e. for more than one field.
Also, is there a solution to structure a multidimensional array depending on more than two fields?
I think it's not a way of asking the question. It is very simple , you can do this by playing with arrays,keys and etc.... So first you should try hard for the problem. After If you have any problem in the middle of your tries then you can ask that here. I have solved your problem here is the complete code , but next time please do some work and then only post the problem. Never ask for the code.
foreach ($initialarray as $key1=>$val1)
{
foreach ($val1 as $key2=>$val2)
{
if($key2=='unit')
{
$num=$val2;
if($val2!=$num)
$testarr['unit'.$val2]=array();
}
if($key2=='class')
{
$testarr['unit'.$num]['class'.$val2][]=$val1;
}
}
}
print_r($testarr);
I must offer a better way for you and future researchers...
You only need one loop, and you merely need to nominate the result array's key values before using [] to "push" new data into the deepest subarray.
*there is absolutely no need for any condition statements or a second loop.
Code: (Demo)
$initialarray = [
['unit' => 1, 'class' => 1, 'value' => 'string1'],
['unit' => 1, 'class' => 2, 'value' => 'string2'],
['unit' => 1, 'class' => 2, 'value' => 'string3'],
['unit' => 2, 'class' => 1, 'value' => 'string4'],
['unit' => 2, 'class' => 2, 'value' => 'string5']
];
foreach ($initialarray as $row) {
$result[$row['unit']][$row['class']][] = $row;
}
var_export($result);
Output:
array (
1 =>
array (
1 =>
array (
0 =>
array (
'unit' => 1,
'class' => 1,
'value' => 'string1',
),
),
2 =>
array (
0 =>
array (
'unit' => 1,
'class' => 2,
'value' => 'string2',
),
1 =>
array (
'unit' => 1,
'class' => 2,
'value' => 'string3',
),
),
),
2 =>
array (
1 =>
array (
0 =>
array (
'unit' => 2,
'class' => 1,
'value' => 'string4',
),
),
2 =>
array (
0 =>
array (
'unit' => 2,
'class' => 2,
'value' => 'string5',
),
),
),
)
If I may express myself in the following manner: I only see the front-end of your problem and know nothing about its back-end, e.g. "Where does the data come from?", "How is it collected and stored", etc. so my answer might not be a real help but still I'll give my "tuppence".
If you can store all that data in a relational database (in form of table(s)) it would be much more easier and faster(!) to select the needed data from the database instead of rearranging arrays, which will take some more time in comparison.
Just as an example you might then select (and store it into an array) all items which have unit = '1' and / or all items which have class = '2'. That would make life much more easier IMHO, than having all the data in a multidimensional array and then try to sort it / rearrange it. Especially if you do that based on more than one property.

Array diff of specific key within multi-dimensional array

I have two arrays of products, both formatted exactly the same, like so:
$products = array(
[0] => array(
['product_id'] => 33
['variation_id'] => 0
['product_price'] => 500.00
),
[1] => array(
['product_id'] => 48
['variation_id'] => 0
['product_price'] => 600.00
),
)
I would like to be able to return a list of only those products not found in the second array, based on the product ID.
I only care about those NOT found in the second array, not additional ones added to the first, so array_diff won't seem to do the trick.
I suspect you want something like array_udiff. This lets you specify how to compare the two arrays, using a callback function. You just create a callback that compares based on product id's.
I think this satisfies what you want because the array_diff family of functions only compare the first array to the rest, it does not return elements that array2 (or 3, or 4) have that array1 does not.
<?php
$products = array(
0 => array(
'product_id' => 33,
'variation_id' => 0,
'product_price' => 500.00
),
1 => array(
'product_id' => 48,
'variation_id' => 0,
'product_price' => 600.00
)
);
$products2 = array(
1 => array(
'product_id' => 48,
'variation_id' => 0,
'product_price' => 600.00
),
2 => array(
'product_id' => 49,
'variation_id' => 0,
'product_price' => 600.00
)
);
function compare_ids($a, $b)
{
return $b['product_id'] - $a['product_id'];
}
var_dump(array_udiff($products, $products2, "compare_ids"));
?>
Outputs:
array(1) {
[0]=>
array(3) {
["product_id"]=>
int(33)
["variation_id"]=>
int(0)
["product_price"]=>
float(500)
}
}
A simple foreach loop should be enough:
<?php
$products = array(
0 => array(
'product_id' => 33,
'variation_id' => 0,
'product_price' => 500.00
),
1 => array(
'product_id' => 48,
'variation_id' => 0,
'product_price' => 600.00
)
);
$products2 = array(
1 => array(
'product_id' => 48,
'variation_id' => 0,
'product_price' => 600.00
),
2 => array(
'product_id' => 49,
'variation_id' => 0,
'product_price' => 600.00
)
);
$diff = array();
// Loop through all elements of the first array
foreach($products2 as $value)
{
// Loop through all elements of the second loop
// If any matches to the current element are found,
// they skip that element
foreach($products as $value2)
{
if($value['product_id'] == $value2['product_id'])
continue 2;
}
// If no matches were found, append it to $diff
$diff[] = $value;
}
The $diff array would then only hold the following value:
array (
0 =>
array (
'product_id' => 49,
'variation_id' => 0,
'product_price' => 600,
),
)
Hope this helped!

Categories