Remove only Key from Multidimensional Associative Array in PHP - php

I want to remove only key from multidimensional associative array preserving its value in PHP.
I've tried with foreach loop.
foreach($collections as $k=>$v){
foreach($v as $k1=>$v1){
foreach($v1 as $k2=>$v2){
if($k2 == 'attr_id'){
unset($collections[$k][$k1][$k2]);
}
}
}
}
I've an array like below:
$collections = [
0 => [
0 => [
"attr_id" => 23,
"value" => "Single Side"
],
1 => [
"attr_id" => 23,
"value" => "Double Side"
],
],
1 => [
0 => [
"attr_id" => 31,
"value" => "A4"
],
1 => [
"attr_id" => 31,
"value" => "12x18"
],
2 => [
"attr_id" => 31,
"value" => "B5"
],
3 => [
"attr_id" => 31,
"value" => "A5"
]
]
];
And I want output Like this:
$collections = [
23 => [ "Single Side", "Double Side" ],
31 => [ "A4", "12x18", "B5", "A5" ]
];
Please Help!

Short solution:
$expected = [];
foreach ($collections as $collection) {
$expected[$collection[0]['attr_id']] = array_column($collection, 'value');
}

You can do this with simply using two foreach() loop and push the value to attr_id
$expected = [];
foreach($collections as $k=>$v){
foreach($v as $k1=>$v1){
$expected[$v1['attr_id']][] = $v1['value'];
}
}
print_r($expected);
Output:
Array (
[23] => Array (
[0] => Single Side
[1] => Double Side
)
[31] => Array (
[0] => A4
[1] => 12x18
[2] => B5
[3] => A5
)
)
DEMO: https://3v4l.org/JlsIl

Do with array_values and array_reduce
first merge all subArray's to one array
The use reduce to apppend value based with attr_id matching
Sandbox demo
$res = call_user_func_array('array_merge',array_values($arr));
$res = array_reduce($res,function($a,$b){
$a[$b['attr_id']] = isset($a[$b['attr_id']]) ? $a[$b['attr_id']] : [] ;
array_push($a[$b['attr_id']],$b['value']);
return $a;
},[]);
print_r($res);

Related

Explode and transpose nominated comma-separated strings of an associative array

I have an array with comma-separated values like below:
array:5 [
"manufacturer" => "BB"
"width" => "245,225, ..."
"height" => "45,65, ..."
"diameter" => "19,17, ..."
"type" => "AA"
]
There is no limit to how many comma-separated values there may be, but all 3 of them will have same length.
From this, I want to get transposed output like below:
[
245,
45,
19,
],
[
45,
65,
17
]
So far, I have tried following code.
$mandatoryFields = [
'width',
'height',
'diameter',
];
$finalArray = [];
for ($i = 0; $i < 2; $i+=1) {
foreach ($mandatoryFields as $mandatoryField) {
$fieldArray = explode(',', $executionArray[$mandatoryField]);
$finalArray[] = [
$fieldArray[$i]
];
}
}
dd($finalArray);
But it is returning me:
array:6 [
0 => array:1 [
0 => "245"
]
1 => array:1 [
0 => "45"
]
2 => array:1 [
0 => "19"
]
3 => array:1 [
0 => "225"
]
4 => array:1 [
0 => "65"
]
5 => array:1 [
0 => "17"
]
]
The following logic might help you solve your issue:
<?php
$arr = [
"manufacturer" => "BB",
"width" => "245, 225",
"height" => "45, 65",
"diameter" => "19, 17",
"type" => "AA",
];
foreach ($arr as $key => $val) {
$split[$key] = explode(',', $val);
}
$mandatoryFields = [
'width',
'height',
'diameter',
];
// keep only mandatory fields
$split = array_intersect_key($split, array_flip($mandatoryFields));
$items = count($split[$mandatoryFields[0]]); // number of 'items' per mandatory field
for ($i = 0; $i < $items; $i++) {
$result[$i] = array_column($split, $i);
}
echo '<pre>';
print_r($result);
echo '</pre>';
Output:
Array
(
[0] => Array
(
[0] => 245
[1] => 45
[2] => 19
)
[1] => Array
(
[0] => 225
[1] => 65
[2] => 17
)
)
Essentially, this is an "explode & transpose" task. If the required columns are known, then they can be hardcoded like this: (Demo)
var_export(
array_map(
null,
explode(', ', $arr['width']),
explode(', ', $arr['height']),
explode(', ', $arr['diameter'])
)
);
Output:
array (
0 =>
array (
0 => '245',
1 => '45',
2 => '19',
),
1 =>
array (
0 => '225',
1 => '65',
2 => '17',
),
)
If the columns need to be dynamic, then map the required fields, explode on commas and unpack the generated rows to maintain a functional coding style: (Demo)
var_export(
array_map(
null,
...array_map(
fn($f) => explode(', ', $arr[$f]),
$mandatoryFields
)
)
);

How to insert items into existing array

Assume I have two arrays as below
array:2 [
0 => {#1995
+"id": 6
+"sales_target_amount": "30000.00"
}
1 => {#1996
+"id": 10
+"sales_target_amount": "1000.00"
}
]
second array
array:2 [
0 => {#1994
+"sales_total": "4165.80"
+"staff_id": 6
}
1 => {#1513
+"sales_total": "1335.60"
+"staff_id": 10
}
]
I'm trying to insert the first array sales_target_amount into the second array if the id is matched to the staff_id.
code
$sum = array_merge($second_array[],$firs_array);
The code above will merge the two array together but not insert the items based on the id.
Expected Result
array:2 [
0 => {#1994
+"sales_total": "4165.80"
+"staff_id": 6
+"sales_target_amount": "30000.00"
}
1 => {#1513
+"sales_total": "1335.60"
+"staff_id": 10
+"sales_target_amount": "1000.00"
}
]
Here is the snippet, please see inline doc for explanation
$arr = [
0 => ["sales_total" => "4165.80", "staff_id" => 6],
1 => ["sales_total" => "1335.60", "staff_id" => 10],
];
$arr1 = [
0 => ["id" => 6, "sales_target_amount" => "30000.00"],
1 => ["id" => 10, "sales_target_amount" => "1000.00"],
];
//NULL to return complete arrays or objects and staff id will be key
$arr = array_column($arr, null, 'staff_id');
// mapping id sales target amount combination
$temp = array_column($arr1, 'sales_target_amount', 'id');
foreach ($arr as $key => $value) {
$arr[$key]['sales_target_amount'] = $temp[$key]; // putting sales_target_amount for id
}
array_column — Return the values from a single column in the input array
Demo Link.
Use hashed map to group values by staff_id
<?php
$arr1 = [
[
'id' => 6,
'sales_target_amount' => '30000.00'
],
[
'id' => 10,
'sales_target_amount' => '1000.00'
]
];
$arr2 = [
[
'sales_total' => '4165.80',
'staff_id' => 6
],
[
'sales_total' => '1335.60',
'staff_id' => 10
]
];
$results = [];
foreach ($arr1 as $value) {
$results[$value['id']] = [
'sales_target_amount' => $value['sales_target_amount']
];
}
foreach ($arr2 as $value) {
$results[$value['staff_id']] = array_merge($results[$value['staff_id']], $value);
}
print_r(array_values($results));
array_merge() do not work with multidimensional array.
Try to use array_merge_recursive().
And you not need use square brackets in this context.
Run function just like
$sum = array_merge_recursive($second_array, $firs_array);
Sort answer using this library
$array = array_merge_recursive(
Arr::flattenSingle(Arr::group($array1, 'id')),
Arr::flattenSingle(Arr::group($array2, 'staff_id'))
);
What it does underneath is to first group your arrays by column you want them merged by. Then because every element in group will have only one corresponding array (cause they are grouped by unique id) flatten those groups to build array with elements like id => array_with_that_id. And then merge those flattened groups by keys which in these case are ids.
Overall this will produce
Array (
[6] => Array (
[id] => 6
[sales_total] => 4165.8
[staff_id] => 6
[sales_target_amount] => 30000
)
[10] => Array (
[id] => 10
[sales_total] => 1335.6
[staff_id] => 10
[sales_target_amount] => 1000
)
)

Creating a associative array in php from a larger multidimensional array

Im having trouble extracting some information from a large array and placing it in a smaller array, the large array i have is as follows;
Array
(
[0] => Array
(
[BlanketBrand] => Array
(
[BlanketBrandID] => 125
[BlanketBrandName] => Neptune
[BlanketBrandActive] => Y
)
)
[1] => Array
(
[BlanketBrand] => Array
(
[BlanketBrandID] => 126
[BlanketBrandName] => King Size
[BlanketBrandActive] => Y
)
)
)
What i would like is to create an array from this with just the BlanketBrandID as the key and the BlanketBrandName as the value
array(
125 => Neptune,
126 => King Size
)
Something like that so its easier for me to work with.
Any help would be great.
Thanks
This can be done in a very simple foreach loop:
<?php
$array = [
[
'BlanketBrand' => [
'BlanketBrandID' => 125,
'BlanketBrandName' => 'Neptune',
'BlanketBrandActive' => 'Y'
]
],
[
'BlanketBrand' => [
'BlanketBrandID' => 126,
'BlanketBrandName' => 'King Size',
'BlanketBrandActive' => 'Y'
]
]
];
$new_array = [];
foreach ($array as $item) {
$new_array[ $item['BlanketBrand']['BlanketBrandID'] ] = $item['BlanketBrand']['BlanketBrandName'];
}
print_r($new_array);
See example here.
You can also accomplish this with array_reduce():
$new_array = array_reduce($array, function($a, $b) {
$a[ $b['BlanketBrand']['BlanketBrandID'] ] = $b['BlanketBrand']['BlanketBrandName'];
return $a;
}, []);
See example here.

How to group an array of associative arrays and declare custom keys?

Can someone help me with converting a php array in a grouped format? I am trying to group them by id. I would like to have the following array converted:
$Arr1=Array
(
0 => Array
(
"id" => "4123",
"test_number" => "1",
"sat_total" => "1050"
),
1 => Array
(
"id" => "4123",
"test_number" => "2",
"sat_total" => "1130"
),
2 => Array
(
"id" => "4123",
"test_number" => "3",
"sat_total" => "1120"
),
3 => Array
(
"id" => "5555",
"test_number" => "1",
"sat_total" => "1130"
),
4 => Array
(
"id" => "5555",
"test_number" => "2",
"sat_total" => "1160"
)
);
into this:
$Arr2=Array
(
0 => Array
(
"id" => "4123",
"Score1" => "1050",
"Score2" => "1130",
"Score3" => "1120"
),
1 => Array
(
"id" => "5555",
"Score1" => "1130",
"Score2" => "1160"
)
);
I have tried a little bit, but can't seem to find how to make it work.
You only need to iterate your rows of data, determine if each row is the first occurring id value or not, then either declare the initial values, or add a variably keyed element to the group. When the loop finishes, call array_values() to reindex the array (remove the temporary keys).
Code: (Demo)
$Arr1=[
["id" => "4123", "test_number" => "1", "sat_total" => "1050"],
["id" => "4123", "test_number" => "2", "sat_total" => "1130"],
["id" => "4123", "test_number" => "3", "sat_total" => "1120"],
["id" => "5555", "test_number" => "1", "sat_total" => "1130"],
["id" => "5555", "test_number" => "2", "sat_total" => "1160"]
];
foreach ($Arr1 as $set) {
if (!isset($result[$set['id']])) {
$result[$set['id']] = ['id' => $set['id'], 'Score1' => $set['sat_total']];
} else {
$result[$set['id']]['Score' . sizeof($result[$set['id']])] = $set['sat_total'];
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
'id' => '4123',
'Score1' => '1050',
'Score2' => '1130',
'Score3' => '1120',
),
1 =>
array (
'id' => '5555',
'Score1' => '1130',
'Score2' => '1160',
),
)
This method will find the scores matching the $id.
It uses three array_intersects to match all the values correct.
This method will only loop the number of unique IDs, in your case two times.
Plus the times to create the score keys.
I do agree with what ggorlen says about the keys. That will also create a more efficient code.
$ids = array_column($Arr1, "id");
$sat = array_column($Arr1, "sat_total");
foreach(array_unique($ids) as $id){
$new[$id] = ["id" => $id];
$tmp = array_values(array_intersect_key($sat,array_intersect_key($Arr1, array_intersect($ids, [$id]))));
for($i=1;$i<=count($tmp);$i++) $new[$id]["Score" . $i] = $tmp[$i-1];
}
var_dump($new);
https://3v4l.org/ag3To
The output is an associative array with id as key.
You can use array_values if you want to make it indexed.
Just to show how much more efficient the code can be with one score array.
This is what it would look like:
$ids = array_column($Arr1, "id");
$sat = array_column($Arr1, "sat_total");
foreach(array_unique($ids) as $id){
$new[] = ["id" => $id, "scores" => array_values(array_intersect_key($sat,array_intersect_key($Arr1, array_intersect($ids, [$id]))))];
}
var_dump($new);
https://3v4l.org/mdA0W
$arr2 = [];
$i = 0;
$length = count($arr1);
do {
$builder = $arr1[$i];
// grab the first item from the original array
$builder = [
// set its initial properties
'id' => $arr1[$i]['id'],
'Score1' => $arr1[$i]['sat_total'],
];
// initialise the subsequent score number
$testNumber = 2;
// prepare to look ahead in the original array for a matching id
while (($i + 1) < $length) { // only look ahead if it is possible to
if ($arr1[$i + 1]['id'] == $builder['id']) {
// did you find a matching id? if so, let's set the subsequent score
$builder["Score$testNumber"] = $arr1[$i + 1]['sat_total'];
$testNumber++; // increase the next score number
$i++; // increase the original array index
} else {
// no luck? let's go forwards and set the next record
break;
}
}
$arr2[] = $builder; // set the built record into the new array
$i++; // move the pointer forwards
} while ($i < $length); // as long as there are items ahead
Not often you get to use a do-while. But it works :)
Feed it your original array $arr1 and $arr2 will be set.
It works by looking forward for matching ids. This solution assumes your original array is ordered by id! So unless you trust the input - don't use this solution!
Otherwise this is a simple, fast, and fairly readable solution to what looks to me like a school exercise?
If you want something that is safe, the other solutions here are suitable.
I'm not sure this structure is ideal--it seems like your keys "Score1", "Score2" etc would be best as an array like scores => [1050, 1130, ...] and it feels like the ids should be keys in the result array. But in any case, this gives your requested output:
$res = [];
foreach ($arr as $e) {
if (!array_key_exists($e['id'], $res)) {
$res[$e['id']] = [];
}
$res[$e['id']]["Score".(count($res[$e['id']])+1)] = $e['sat_total'];
}
$count = 0;
foreach ($res as $k => $v) {
$res[$k]['id'] = $k;
$res[$count++] = $res[$k];
unset($res[$k]);
}
print_r($res);
Output
Array
(
[0] => Array
(
[Score1] => 1050
[Score2] => 1130
[Score3] => 1120
[id] => 4123
)
[1] => Array
(
[Score1] => 1130
[Score2] => 1160
[id] => 5555
)
)
Note that I did two passes which is a little verbose, but taking the time to key in the data ids into the array in the first pass should improve a linear search through the array for each element into O(1) hashing, so I think it's worth the extra loop block.

Check same value in array

I have the following array:
$teams = [["id" => 1, "address" => "A1"],["id" => 2, "address" => "A1"],["id" => 3, "address" => "A2"]];
How can I check and get the teams with the same address? My output should be Team ID 1 and 2? Consider that I cannot use hard coded address. The data is dynamic and is coming from the database.
In php, laravel.
Thank you in advance!
Another way to do this is to use array_column() and array_count_values(). Then use array_filter() to remove elements with no duplicates:
$teams = [
["id" => 1, "address" => "A1"],
["id" => 2, "address" => "A1"] ,
["id" => 3, "address" => "A2"]
];
$dups = array_count_values(array_column($teams, 'address'));
$teams = array_filter($teams, function($item) use($dups) {
return $dups[$item['address']] > 1;
});
print_r($teams);
Outputs (reformatted):
Array
(
[0] => Array([id] => 1, [address] => A1)
[1] => Array([id] => 2, [address] => A1)
)
First you need to group by their address and then you can use array_filter() to truncate your array based on criteria:
<?php
$teams = [["id" => 1, "address" => "A1"],["id" => 2, "address" => "A1"],["id" => 3, "address" => "A2"]];
// Set a new array
$filtered = [];
// Loop the teams
foreach($teams as $v)
{
// Group the teams into their respective addresses
$filtered[$v['address']][] = $v;
}
// Filter out any address with 1 or fewer teams
$filtered = array_filter($filtered, function($v){
return count($v) > 1;
});
print_r($filtered);
// Now you can loop $filtered and display whatever you want
Output:
Array
(
[A1] => Array
(
[0] => Array
(
[id] => 1
[address] => A1
)
[1] => Array
(
[id] => 2
[address] => A1
)
)
)
Go through the array, remember which addresses are used by which team. When there is more than one team stored at a key (address), you found a duplicate:
<?php
$teams = [
["id" => 1, "address" => "A1"]
,["id" => 2, "address" => "A1"]
,["id" => 3, "address" => "A2"]
];
function findDuplicates($teams) {
$addresses = [];
foreach ($teams as $team) {
if (!isset($addresses[$team["address"]])) {
$addresses[$team["address"]] = [];
}
$addresses[$team["address"]][] = $team["id"];
}
foreach ($addresses as $address => $teamsHere) {
if (count($teamsHere) > 1) {
echo "Teams with same address (" . $address . "): " . join(",", $teamsHere) . "\n";
}
}
}
findDuplicates($teams);
Try it online!
Edit: a less "clunky" approach, using array_* functions:
<?php
$teams = [
["id" => 1, "address" => "A1"]
,["id" => 2, "address" => "A1"]
,["id" => 3, "address" => "A2"]
];
function findDuplicates($teams) {
$addresses = array_column($teams, "address");
$counts = array_count_values($addresses);
return array_filter($teams, function($team) use ($counts) { return $counts[$team["address"]] > 1; });
}
print_r(findDuplicates($teams));
Try it online!

Categories