My array structure is as follows -
[
[
"points" => 10,
"details" => ["name" => "Team A", "rank" => ""]
],
[
"points" => 10,
"details" => ["name" => "Team B", "rank" => ""]
],
[
"points" => 8,
"details" => ["name" => "Team C", "rank" => ""]
],
[
"points" => 6,
"details" => ["name" => "Team D", "rank" => ""]
],
]
Now I want populate the array's "rank" value with the appropriate dense rank. Expected result:
[
[
"points" => 10,
"details" => ["name" => "Team A", "rank" => 1]
],
[
"points" => 10,
"details" => ["name" => "Team B", "rank" => 1]
],
[
"points" => 8,
"details" => ["name" => "Team C", "rank" => 2]
],
[
"points" => 6,
"details" => ["name" => "Team D", "rank" => 3]
],
]
How can I achieve this output? I tried looping through each element in the array and comparing points, but I didn't find that to be really efficient.
How about to create another array and store desired result there
$array = array(
array(
"points" => 10,
"details" => array(
"name" => "Team A",
"rank" => ""
)
),
array(
"points" => 11,
"details" => array(
"name" => "Team B",
"rank" => ""
)
)
);
$c = 0; // count identifier
$n = array(); // create new array
for ($i=0;$i<count($array);$i++){ // loop through each array
foreach ($array[$i] as $value){ // loop through into sub arrays
if (is_array($value)){
$n[$i]['details'] = array(
"name" => $value['name'],
"rank" => $c
);
$c++;
} else {
$n[$i]['points'] = $value;
}
}
}
print_r($n);
Output will be:
Array ( [0] => Array ( [points] => 10 [details] => Array ( [name] => Team A [rank] => 0 ) ) [1] => Array ( [points] => 11 [details] => Array ( [name] => Team B [rank] => 1 ) ) )
A bit bruteforce but it should work.
$array = array(
array(
"points" => 10,
"details" => array(
"name" => "Team A",
"rank" => ""
)
),
array(
"points" => 11,
"details" => array(
"name" => "Team B",
"rank" => ""
)
),
array(
"points" => 10,
"details" => array(
"name" => "Team A",
"rank" => ""
)
),
array(
"points" => 11,
"details" => array(
"name" => "Team B",
"rank" => ""
)
)
);
$points = array();
foreach($array as $key => $arr){
$points[] = $arr['points'];
}
asort($points);
foreach($points as $pkey => $point){
foreach($array as $akey => $arr){
if($point == $arr['points']){
$array[$akey]['details']['rank'] = $pkey+1;
}
}
}
var_dump($array);
Since your multidimensional input array is already sorted descending by the points column, you can loop through the array and modify its rank data by reference while conditionally incrementing the rank variable.
Code: (Demo)
$denseRank = 0;
foreach ($array as ['points'=> $points, 'details' => ['rank' => &$rank]]) {
$denseRanks[$points] ??= ++$denseRank;
$rank = $denseRanks[$points];
}
var_export($array);
The above snippet uses "array destructuring" in the foreach() to declare only used variables; it is just as viable to declare &$row and then access its elements in the loop's body.
Related
I need to restructure an array containing data in 2 levels and 3 levels. All of the values should be grouped by their indexes, but I need to maintain associative relationships.
Sample input:
$variation = [
"sku" => [
0 => "dSADad",
1 => "ASDAF",
2 => "ASFAS",
],
"Price" => [
0 => "1",
1 => "1",
2 => "1",
],
"Quantity" => [
0 => "123",
1 => "123",
2 => "123434",
],
"attributes" => [
"Color" => [
0 => "5",
1 => "4",
2 => "4",
],
"Size" => [
0 => "3",
1 => "3",
2 => "2",
],
"Material" => [
0 => "7",
1 => "7",
2 => "8",
],
],
];
I want to transform it to be grouped by separate variants. I tried several options but without a successful result. I also tried with JS to add an index to the input before submitting, but it still doesn't work. The only option left is to transform it into PHP.
Desired result:
$variations = [
[
"sku" => "dSADad",
"Price" => "1",
"Quantity" => "123",
"attributes" => [
"Color" => "5",
"Size" => "3",
"Material" => "7",
],
],
[
"sku" => "ASDAF",
"Price" => "1",
"Quantity" => "123",
"attributes" => [
"Color" => "4",
"Size" => "3",
"Material" => "7",
],
],
[
"sku" => "ASFAS",
"Price" => "1",
"Quantity" => "123434",
"attributes" => [
"Color" => "4",
"Size" => "2",
"Material" => "8",
],
],
];
I managed to make this piece of code:
function extractVariation($variations, $key)
{
$variation = [];
foreach ($variations as $property => $values) {
if (isset($values[$key])) {
$variation[$property] = $values[$key];
} else {
$variation[$property] = extractVariation($values, $key);
}
}
return $variation;
}
$newVariations = [];
foreach ($variations['sku'] as $key => $sku) {
$newVariations[] = extractVariation($variations, $key);
}
var_export($newVariations);
See a working example here: https://3v4l.org/l4gJQ
Note that I renamed your $variation array into $variations.
The function is recursive, which allows it to go into the attributes array.
The output is:
array (
0 =>
array (
'sku' => 'dSADad',
'Price' => '1',
'Quantity' => '123',
'attributes' =>
array (
'Color' => '5',
'Size' => '3',
'Material' => '7',
),
),
1 =>
array (
'sku' => 'ASDAF',
'Price' => '1',
'Quantity' => '123',
'attributes' =>
array (
'Color' => '4',
'Size' => '3',
'Material' => '7',
),
),
2 =>
array (
'sku' => 'ASFAS',
'Price' => '1',
'Quantity' => '123434',
'attributes' =>
array (
'Color' => '4',
'Size' => '2',
'Material' => '8',
),
),
)
It is always better to show what you've tried, even if it doesn't work completely. That way people here can see that you're not simply asking them to write code for you, but that you really have a problem.
For your sample data, it is not necessary to use recursion because the input array's depth is known/static.
Traditional array transposition (with a 2d array) is the nesting of two foreach loops and switching the keys between the two levels. With your data, you must conditionally handle the data sets that have 3 levels of depth. Notice the how inside of the is_array() condition, another loop is used to iterate the subarray and push that data into the new appropriate position in the result array.
In all cases, the level containing indexed keys is used as the new first level key and the original first level keys are always used as new second level keys.
Code: (Demo)
$result = [];
foreach ($array as $k1 => $v1) {
foreach ($v1 as $k2 => $v2) {
if (is_array($v2)) {
foreach ($v2 as $k3 => $v3) {
$result[$k3][$k1][$k2] = $v3;
}
} else {
$result[$k2][$k1] = $v2;
}
}
}
var_export($result);
I have some cases where I need to do a split item for my shipment from items order.
the rule is max weight per 1 shipment is 5.
this is my items order :
$items = [
[
"sku" => "SKU-A",
"name" => "Product A",
"weight" => 7,
"dimension" => "20x30x10"
],
[
"sku" => "SKU-B",
"name" => "Product B",
"weight" => 4,
"dimension" => "10x10x20"
],
];
after doing split, i expect the result to this:
// will create new array
// limit weight per shipment max 5kg
$item1 = [
[
"sku" => "SKU-A",
"name" => "Product A",
"weight" => 5,
"dimension" => "20x30x10"
]
];
$item2 = [
[
"sku" => "SKU-A",
"name" => "Product A",
"weight" => 2,
"dimension" => "20x30x10"
], // this item from SKU-A where w => 7 - 5 = 2
[
"sku" => "SKU-B",
"name" => "Product B",
"weight" => 3,
"dimension" => "10x10x20"
],
];
$item3 = [
[
"sku" => "SKU-B",
"name" => "Product B",
"weight" => 1,
"dimension" => "10x10x20"
],// this item from SKU-B where w => 7 - 5 = 2
];
what's the posible way to do that? thank you.
#catLovers, I have made this code as desired... Please improvise/ optimise as necessary.
$items = [
[
"sku" => "SKU-A",
"name" => "Product A",
"weight" => 7,
"dimension" => "20x30x10"
],
[
"sku" => "SKU-B",
"name" => "Product B",
"weight" => 4,
"dimension" => "10x10x20"
],
];
$newItems = array();
for ($x = 0; $x <= count($items)-1; $x++) {
if ($items[$x]['weight'] > 5) {
$weight = $items[$x]['weight'];
$wt =5;
do {
$temp = array([
'sku' => $items[$x]['sku'],
'name' => $items[$x]['name'],
'weight' => $wt,
'dimension' => $items[$x]['dimension']
]);
array_push($newItems,$temp);
$weight=$weight-5;
if ($weight <=5){ $wt=$weight;}
} while ($weight <= 5);
echo "<pre>";
print_r($temp);
echo "</pre>";
}
else {
array_push($newItems,$items[$x]);
}
}
echo "<pre>";
print_r($newItems);
echo "</pre>";
I have 2 arrays. The first is my array and the second is the API response :
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
I'd like to remove in array1 all id in array2 who have a status false, or keep all id with status true
In this example I need to get :
$array1 = [
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 12, "name" => "tototo"]
];
Because id 45 and 82 are false in the second array, then I remove them from the first array.
How I can do that without using multiple loops ? There is a solution if we play with php functions like array_diff or something like this ?
You can use array_filter to filter the $array1. Return true if id exist and status is true.
$array1 = ...
$array2 = ...
$result = array_filter($array1, function( $o ) use( $array2 ) {
return isset( $array2[ $o["id"] ] ) && $array2[ $o["id"] ]["status"];
});
This will result to:
Array
(
[1] => Array
(
[id] => 50
[name] => tata
)
[2] => Array
(
[id] => 31
[name] => titi
)
[4] => Array
(
[id] => 12
[name] => tototo
)
)
The most readable solution is often better than using fancy array_* functions, i.e. in this case a simple foreach loop is sufficient:
https://3v4l.org/5eNEf
<?php
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
$result = [];
foreach($array1 as $arrayEl) {
$id = $arrayEl['id'];
if($array2[$id]['status'] === true) {
$result[] = $arrayEl;
}
}
var_dump($result);
Note: We are not modifying the original content but create a new result array. You might want to add additional isset checks depending on what keys your array contains/might not contain.
Please try this code.
<?php
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
foreach($array1 AS $key => $value){
if(!$array2[$value['id']]['status']){
unset($array1[$key]);
}
}
echo "<pre>";
print_r($array1);
?>
Find the key from first array and unset it using the true or false value.
Output:
Array
(
[1] => Array
(
[id] => 50
[name] => tata
)
[2] => Array
(
[id] => 31
[name] => titi
)
[4] => Array
(
[id] => 12
[name] => tototo
)
)
You can use array_walk
$res=[];
array_walk($array1, function(&$v,$k) use (&$res,$array2){
($array2[$v['id']]['status'] == 1) ? ($res[] = $v): '';
});
Live Demo
Here is one more solution for the same,
array_walk($array1, function(&$item,$key) use(&$array1, $array2){
if(!$array2[$item['id']]['status']) // checking status if false
unset($array1[array_search($item['id'], array_column($array1,'id'))]); // then unset
});
print_r($array1);
array_walk — Apply a user supplied function to every member of an array
array_search — Searches the array for a given value and returns the first corresponding key if successful
array_column — Return the values from a single column in the input array
Working demo.
This is probably the least readable solution :-)
Array_intersect and array_column can also get the job done.
I make both arrays associative on id then use array_intersect_key to get the true values.
// Make $array1 associative.
$array1 = array_column($array1, null, "id");
// Find all true values in $array1 from $array2
$result = array_intersect_key($array1, array_intersect(array_combine(array_keys($array2), array_column($array2, "status")), [true]));
https://3v4l.org/QVoI5
$array1 = [
["id" => 45, "name" => "toto"],
["id" => 50, "name" => "tata"],
["id" => 31, "name" => "titi"],
["id" => 82, "name" => "tutu"],
["id" => 12, "name" => "tototo"]
];
$array2 = [
"45" => ["status" => false],
"50" => ["status" => true],
"31" => ["status" => true],
"82" => ["status" => false],
"12" => ["status" => true]
];
foreach ($array1 as $tocheck) {
if ($array2[$tocheck['id']]['status']) {
$new[] = $tocheck;
}
}
print_r($new);
I want to create dynamic menu with looping an array be 1 object menu. But error occured.
Our code is below it:
$menus = [{"id" => 1, "label" => "content", "parent_id" => 0},{"id" => 2, "label" => "inbox", "id" => 3, "parent_id" => 0}, {"id" => 4, "label" => "item", "parent_id" => 0}];
$sub_menus = [{"id" => 5, "label" => "banner", "parent_id" => 1},{"id" => 6, "label" => "ads", "parent_id" => 1}];
foreach($menus as $row => $value){
$nav[$row] = $value;
foreach($sub_menus as $r => $v) {
if($v['parent_id'] == $value['id']){
$nav[$row]['sub_menu'][$r] = $v;
}
}
}
I get error notif, "Indirect modification of overloaded element of App\Menu has no effect"
Please Help me :)
The code is working. You have a lot of bugs in your arrays.
Fixed:
$menus = [
[
"id" => 1,
"label" => "content",
"parent_id" => 0
],
[
"id" => 2,
"label" => "inbox",
"parent_id" => 0
],
[
"id" => 4,
"label" => "item",
"parent_id" => 0
]
];
$sub_menus = [
[
"id" => 5,
"label" => "banner",
"parent_id" => 1
],
[
"id" => 6,
"label" => "ads",
"parent_id" => 1
]
];
foreach($menus as $row => $value){
$nav[$row] = $value;
foreach($sub_menus as $r => $v) {
if($v['parent_id'] == $value['id']){
$nav[$row]['sub_menu'][$r] = $v;
}
}
}
You have a broken array, something like an incorrect conversion of json to an array;
You can test(execute) it here (working example)
I have an array like this:
$array = array(
0 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "memory"),
1 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "cpu"),
2 => array("ordernumber" => "1", "name" => "John", "product" => "desktop", "component" => "cpu"),
3 => array("ordernumber" => "2", "name" => "Pete", "product" => "monitor", "component" => "")
);
It contains data from different orders, but as you can see an order can contain multiple purchased products, and each product can contain different 'components'. There's alot of duplicate data in this array, so I would like to turn it into this:
$array = array(
0 => array(
"order" => array(
"ordernumber" => "1", "name" => "John"
),
"products" => array(
0 => array(
"name" => "laptop",
"components" => array("memory", "cpu")
),
1 => array(
"name" => "desktop",
"components" => array("cpu")
)
)
),
1 => array(
"order" => array(
"ordernumber" => "2", "name" => "Pete"
),
"products" => array(
0 => array(
"name" => "monitor",
"components" => array()
)
)
)
);
What would be a good way to do this?
Please use below code to make the solution what you want
<?php
$array = array(
0 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "memory"),
1 => array("ordernumber" => "1", "name" => "John", "product" => "laptop", "component" => "cpu"),
2 => array("ordernumber" => "1", "name" => "John", "product" => "desktop", "component" => "cpu"),
3 => array("ordernumber" => "2", "name" => "Pete", "product" => "monitor", "component" => "")
);
$final_array = [];
foreach($array as $k=>$v){
$final_array[$v['ordernumber']]['order']['ordernumber'] = $v['ordernumber'];
$final_array[$v['ordernumber']]['order']['name'] = $v['name'];
$final_array[$v['ordernumber']]['products'][$v['product']]['name'] = $v['product'];
$final_array[$v['ordernumber']]['products'][$v['product']]['components'][] = $v['component'];
}
// You can skip this foreach if there will not metter of KEY of an array in your code!
$final_array = array_values($final_array);
foreach($final_array as $k=>$v){
$final_array[$k]['products'] = array_values($final_array[$k]['products']);
}
echo "<pre>";
print_r($final_array);
?>
its should work!!