This question already has answers here:
Remove unwanted elements from subarrays in multidimensional array
(3 answers)
Closed 6 months ago.
I have a multi dimensional array like below.
array:1 [
0 => array:3 [
"picture_id" => "0"
"car_name" => "CA"
"from" => "2020"
"to" => "2020"
]
]
I need to remove from & to from the above array and return result in same structure.
I have tried following code
$whitelist = array("from", "to");
$finalArray = [];
foreach ($records as $record) {
foreach ($record as $key => $item) {
if (!in_array($key, $whitelist)) {
$finalArray[$key] = $item;
}
}
}
But the result I am getting is not multi-dimensional array like this:
array:1 [
"picture_id" => "0"
"car_name" => "CA"
]
My expected result is:
array:1 [
0 => array:3 [
"picture_id" => "0"
"car_name" => "CA"
]
]
You can try something like this:
$array = [
[
"picture_id" => "0",
"car_name" => "CA",
"from" => "2018",
"to" => "2020"
],
[
"picture_id" => "1",
"car_name" => "WA",
"from" => "2010",
"to" => "2019"
]
];
$whitelist = array("from", "to");
$finalArray = [];
foreach ($array as $k => $record) {
foreach ($record as $key => $item) {
if (!in_array($key, $whitelist)) {
$finalArray[$k][$key] = $item;
}
}
}
print("<pre>".print_r($finalArray,true)."</pre>");
What will print out:
Array
(
[0] => Array
(
[picture_id] => 0
[car_name] => CA
)
[1] => Array
(
[picture_id] => 1
[car_name] => WA
)
)
A short explanation...Basically you are looping over multi dimensional array as
foreach($array as $key => $value)
Where value is "inner" array, so in order to remove some elements from inner, and create a new multi dimensionalarray, you have to use keys, like in my example, from original array. So you than actually make an array like:
$newArray[$key] = $innerArray
And this gives you multi dimensional array.
BR
Rather than having to go through each field to determine if it should be removed, you can use array_diff_key() to remove all of the columns in one go. This needs you to create a list of the fields you want to remove and for each record just get the difference between the record and the keys to remove...
// Keys to remove (note as key rather than value)
$remove = ["from" => 1, "to" => 1];
$finalArray = [];
foreach ($array as $record) {
$finalArray[] = array_diff_key($record, $remove);
}
print_r($finalArray);
Try This
$result = [];
foreach($yourArray as $key => $value){
unset($value['from']);
unset($value['to']); //You can unset as many columns as you want specifically.
$result[] = $value;
}
print_r($result);
Related
I have an array of arrays of associative arrays like this
$my_array = [
[ 8 => "One" ],
[ 3=>"Two" ]
]
How can I like explode all the associative arrays into one array like this
[
8 => "One",
3 =>"Two"
]
I tried using array_merge(...$my_array) and all it gives is
[
0 => "One"
1 => "Two"
]
in plain php, and assuming those arrays will always look like that:
(if you're not sure you should loop through the sub_array to get the keys)
foreach($my_array as $sub_array ){
$new_array[key($sub_array)] = $sub_array[key($sub_array)];
}
var_export($new_array);
This is how you can do it, by using Collection and the mapWithKeys method :
$a = [
[
8 => "One",
],
[
3 => "Two",
],
];
$b = collect($a)->mapWithKeys(function($a) {
return $a;
})->toArray();
dd($b);
// [
// 8 => "One"
// 3 => "Two"
// ]
Loop through both levels to get the keys
foreach ($my_array as $sub_array) {
foreach ($sub_array as $key => $value) {
$new_array[$key] = $value;
}
}
print_r($new_array);
I have this array:
0 => array:3 [
"product_id" => "1138"
"product_image" => "/resources/medias/shop/products/shop-6500720--1.png"
"product_sku" => "6500722"
]
1 => array:3 [
"product_id" => "1144"
"product_image" => "/resources/medias/shop/products/shop-6501041--1.png"
"product_sku" => "6501046"
]
2 => array:3 [
"product_id" => "113"
"product_image" => "/resources/medias/shop/products/shop-6294909--1.png"
"product_sku" => "6294915"
]
What I am looking for is a way to get a multiple array with only required columns (array_column is not a option, since it's give me only 1 column).
What I have done
function colsFromArray($array, $keys)
{
return array_map(function ($el) use ($keys) {
return array_map(function ($c) use ($el) {
return $el[$c];
}, $keys);
}, $array);
}
$array = array(
[
"product_id" => "1138",
"product_image" => "/resources/medias/shop/products/shop-6500720--1.png",
"product_sku" => "6500722"
],
[
"product_id" => "1144",
"product_image" => "/resources/medias/shop/products/shop-6501041--1.png",
"product_sku" => "6501046"
],
[
"product_id" => "113",
"product_image" => "/resources/medias/shop/products/shop-6294909--1.png",
"product_sku" => "6294915"
]
);
colsFromArray($array, array("product_id", "product_sku"));
//0 => array:3 [
// "product_id" => "1138"
// "product_sku" => "6500722"
// ]
//1 => array:3 [
// "product_id" => "1144"
// "product_sku" => "6501046"
// ]
//2 => array:3 [
// "product_id" => "113"
// "product_sku" => "6294915"
//]
The problem is that it seems too laggy, since it iterates twice over this.
Is there any way to get multiple columns without this workaround?
I'm using PHP5.6
If you need two columns from an array where one is SKU (which generally is unique) then you can use array_column with the third parameter.
$new = array_column($arr, "product_id", "product_sku");
This will return a flat array with the SKU as the key and ID as value making the array easy to work with also.
Output:
array(3) {
[6500722]=>
string(4) "1138"
[6501046]=>
string(4) "1144"
[6294915]=>
string(3) "113"
}
https://3v4l.org/UDGiO
I think the bigger issue is you lose the keys
Original Code
array (
0 =>
array (
0 => '1138',
1 => '6500722',
),
1 =>
array (
0 => '1144',
1 => '6501046',
),
2 =>
array (
0 => '113',
1 => '6294915',
);
You can use a simple foreach instead of the second array_map:
function colsFromArray(array $array, $keys)
{
if (!is_array($keys)) $keys = [$keys];
return array_map(function ($el) use ($keys) {
$o = [];
foreach($keys as $key){
// if(isset($el[$key]))$o[$key] = $el[$key]; //you can do it this way if you don't want to set a default for missing keys.
$o[$key] = isset($el[$key])?$el[$key]:false;
}
return $o;
}, $array);
}
Output
array (
0 =>
array (
'product_id' => '1138',
'product_sku' => '6500722',
),
1 =>
array (
'product_id' => '1144',
'product_sku' => '6501046',
),
2 =>
array (
'product_id' => '113',
'product_sku' => '6294915',
),
)
Sandbox
the problem is that it seems too laggy, since it iterates twice over this.
There is no real way to not iterate over it 2 times, but you probably don't want to throw away the keys either.
That said you can recursively unset the items you don't want.
function colsFromArray(array &$array, $keys)
{
if (!is_array($keys)) $keys = [$keys];
foreach ($array as $key => &$value) {
if (is_array($value)) {
colsFromArray($value, $keys); //recursive
}else if(!in_array($key, $keys)){
unset($array[$key]);
}
}
}
colsFromArray($array, array("product_id", "product_sku"));
var_export($array);
Same output as before
This is easier to do by reference. Rather or not that is faster you'll have to test the 2 and see.
Sandbox
As a final note you shouldn't assume the key will exist or that keys will be an array unless you type cast it as an array.
You could also do it with array filter
function colsFromArray(array $array, $keys)
{
if (!is_array($keys)) $keys = [$keys];
$filter = function($k) use ($keys){
return in_array($k,$keys);
};
return array_map(function ($el) use ($keys,$filter) {
return array_filter($el, $filter, ARRAY_FILTER_USE_KEY );
}, $array);
}
There is some small performance benefit to declaring the function for filtering outside of the loop (array_map).
Sandbox
If you do not want to change your original array and want your desired output
Use array_insersect_key function to get your desired output as following
$array = array(
[
"product_id" => "1138",
"product_image" => "/resources/medias/shop/products/shop-6500720--1.png",
"product_sku" => "6500722"
],
[
"product_id" => "1144",
"product_image" => "/resources/medias/shop/products/shop-6501041--1.png",
"product_sku" => "6501046"
],
[
"product_id" => "113",
"product_image" => "/resources/medias/shop/products/shop-6294909--1.png",
"product_sku" => "6294915"
]
);
$keys = array("product_id"=>1, "product_sku"=>2);
$filteredArray = array_map(function($a) use($keys){
return array_intersect_key($a,$keys);
}, $array);
print_r($filteredArray);
I refactored the elegant approach from #Chayan into a function so it can be used like array_column(). Keys to be filtered can now be presented as a simple array.
Btw this is most likely also the fastest approach, since it uses build-in functions for most of the heavy lifting.
function array_columns(array $arr, array $keysSelect)
{
$keys = array_flip($keysSelect);
return array_map(
function($a) use($keys) {
return array_intersect_key($a,$keys);
},
$arr
);
}
$arr = [
[
"product_id" => "1138",
"product_image" => "/resources/medias/shop/products/shop-6500720--1.png",
"product_sku" => "6500722"
],
[
"product_id" => "1144",
"product_image" => "/resources/medias/shop/products/shop-6501041--1.png",
"product_sku" => "6501046"
],
[
"product_id" => "113",
"product_image" => "/resources/medias/shop/products/shop-6294909--1.png",
"product_sku" => "6294915"
]
];
$keysSelect = ["product_id" , "product_sku"];
$filteredArray = array_columns($arr, $keysSelect);
var_dump($filteredArray);
If I understand your question correctly, you could try a traditional foreach - it might be a little faster.
function colsFromArray($array, $filterKeys) {
$newArr = [];
foreach($array as $val) {
$element = [];
foreach($filterKeys as $filterKey) {
$element[$filterKey] = $val[$filterKey];
}
$newArr[] = $element;
}
}
(Not tested)
The problem is that it seems too laggy, since it iterates twice over this
Your original code isn't iterating twice over the same array. You won't be able to get around iterating over the main array and then the filterKeys array if you want to have an array where each element is another array of elements with keys from the filterKeys array.
This is a refactored function based on Chayan's with added renaming of selected columns:
/** Function - array_columns Selects columns from multidimantional array and renames columns as required
*
* #param array $arr, array $selectColRenameKeys
* example: (NewName1->colNameneeded1,NewName2->colNameneeded2,ect...)
* #return array
* #access public
*
*/
private function array_columns( $arr,$selectColRenameKeys) {
$keys = array_flip($selectColRenameKeys);
$filteredArray = array_map(function($a) use($keys){
$data = array_intersect_key($a,$keys);
$rename_arr= array();
foreach ($data as $colname => $value){
$r_arr[$keys[$colname]]= $value ;
}
return $r_arr;
}, $arr);
return $filteredArray;
}
An added feature to the array_columns function that eventually traces back to Chayan's answer, this time extended from Joseph Mangion's function.
I occasionally have long lists of the selected columns where I want to preserve the keys and don't necessarily want to follow the cumbersome ['orignal_field_name'] => ['original_field_name'] format for a great number of fields.
This version preserves the original key for each field by default unless a new key is specified.
// See answer from Joseph Mangion: https://stackoverflow.com/questions/52706383/php-get-multiple-columns-from-array
/** Function - array_columns Selects columns from multidimensional array and renames columns as required
*
* #param array $in_array, array $select_columns_rename_keys
* example of $select_columns_rename_keys:
* ['new_column_name1' => 'original_column_name1', 'original_column_name2', 'original_column_name3', 'new_column_name4' => 'original_column_name4', ...]
* This will use the original keys for columns 2 and 3 and rename columns 1 and 4
* #return array
* #access public
*
*/
public function array_columns($in_array, $select_columns_rename_keys) {
foreach ($select_columns_rename_keys as $k => $v)
if (is_int($k)) {
$select_columns_rename_keys[$v] = $v;
unset($select_columns_rename_keys[$k]);
}
$keys = array_flip($select_columns_rename_keys);
$filtered_array =
array_map(function($a) use($keys) {
$data = array_intersect_key($a, $keys);
$return_array = [];
foreach ($data as $column_name => $value) $return_array[$keys[$column_name]] = $value;
return $return_array;
}, $in_array);
return $filtered_array;
}
I have array inside array:
{
"0" => array("key" => "code", "id" => "4", "value" => "yes"),
"1" => array("key" => "parameter", "id" => "4", "value" => "0"),
"2" => array("key" => "code", "id" => "5", "value" => "no"),
etc...
}
This is what I want to do: I want to have one dimension array in which key would be "id" and value would be "value". However, I need to filter out entries whose key is "parameters". So, in this example, the final array should look like this:
{
"4" => "yes",
"5" => "no"
}
I just can't seem to figure out how to do this. Could you please help me a bit? I tried writing this foreach inside foreach but I just can't wrap my head around how to filter data.
foreach ($settings AS $key => $value) {
$id = null;
$value = null;
foreach ($value AS $key2 => $value2) {
// No idea how to filter out uneccesary entries and save the correct ones
}
$finalArray[$id] = $value;
}
This should do it :
$finalArray = array();
foreach ($settings as $setting) {
if ($setting['key'] != 'parameter') {
$finalArray[$setting['id']] = $setting['value'];
}
}
Assuming all your entries have keys 'key', 'id' and 'value'.
use array_column and array_filter like this, if you want to filter more keys add them to out_keys array :
<?php
$array = [
["key" => "code", "id" => "4", "value" => "yes"],
["key" => "parameter", "id" => "4", "value" => "0"],
["key" => "code", "id" => "5", "value" => "no"]
];
$out_keys = ['parameter'];
$result = array_column(array_filter($array, function($item) use($out_keys) {
return !in_array($item['key'], $out_keys);
}), 'value', 'id');
echo "<pre>";
print_r($result);
output:
Array
(
[4] => yes
[5] => no
)
Assuming $data is your starting array, the code below will output what you want in $result
$result = [];
foreach(array_filter($data, function($el){return $el['key']!='parameter';}) as $el){
$result[$el['id']] = $el['value'];
}
Live demo
This question already has answers here:
Convert backslash-delimited string into an associative array
(4 answers)
Closed 6 years ago.
I may not be clear enough in the title but here is my problem.
I have a string like this
$chain = "id:20604#*#user_id:32444#*#session_id:0#*#version:142#*#modified:1438610605#*#name:recrutement#*#push:0#*#last_push_execution:0#*#allowempty:1";
I do an explode("#*#", $chain);
and now i have this:
array:9 [
0 => "id:20604"
1 => "user_id:32444"
2 => "session_id:0"
3 => "version:142"
4 => "modified:1438610605"
5 => "name:recrutement"
6 => "push:0"
7 => "last_push_execution:0"
8
]
But i wanna something like this
array:9 [
"id" => "20604"
"user_id" => "32444"
"session_id" => "0"
"version" => "142"
"modified" => "1438610605"
"name" => "recrutement"
"push"=> "0"
"last_push_execution"=> "0"
]
Can anyone show me how to do it ?
thanks
1) Simple solution using explode function:
$chain = "id:20604#*#user_id:32444#*#session_id:0#*#version:142#*#modified:1438610605#*#name:recrutement#*#push:0#*#last_push_execution:0#*#allowempty:1";
$result = [];
foreach (explode("#*#", $chain) as $c) {
$pair = explode(":", $c);
$result[$pair[0]] = $pair[1];
}
2) Alternative solution using preg_match_all and array_combine functions:
$chain = "id:20604#*#user_id:32444#*#session_id:0#*#version:142#*#modified:1438610605#*#name:recrutement#*#push:0#*#last_push_execution:0#*#allowempty:1";
preg_match_all("/\b(\w+):(\w+)\b/", $chain, $matches);
$result = array_combine($matches[1], $matches[2]);
Both approaches will give the needed result
One way to rome.
$final=array();
array_map(
function($a) use (&$final){
list($k,$v)=explode(':',$a);
$final[$k]=$v;
},
explode("#*#", $chain)
);
var_export($final);
Whilst array_map() is a more elegant solution, this is an alternative :
$outArray = array();
$tempArray = explode("#*#", $chain);
foreach ($tempArray as $chainValue) {
$split = explode(':',$chainValue);
$key = $split[0];
$value = $split[1];
$outArray[$key] = $value;
}
You can do it using PHP's explode() method like this:
$arr = [
0 => "id:20604",
1 => "user_id:32444",
2 => "session_id:0",
3 => "version:142",
4 => "modified:1438610605",
5 => "name:recrutement",
6 => "push:0",
7 => "last_push_execution:0",
];
$final_arr = [];
foreach ($arr as $key => $val) {
$a = explode(':', $val);
$final_arr[$a[0]] = $a[1];
}
The final output would be:
$final_arr = array:8 [
"id" => "20604"
"user_id" => "32444"
"session_id" => "0"
"version" => "142"
"modified" => "1438610605"
"name" => "recrutement"
"push" => "0"
"last_push_execution" => "0"
]
Hope this helps!
I'm trying to manipulate an associative multidimensional array. I've extracted the keys from an array that I want to apply to another's values . . .
These are the keys that I've extracted in another function
$keys = array (
"id" => "id",
"addr_street_num" => "addr_street_num",
"addr_street" => "addr_street",
"price" => "price",
"days" =>"days",
"state" => Array
(
"id" => "id",
"name" => "name"
),
"city" => Array
(
"id" => "id",
"web_id" => "web_id",
"name" => "name"
)
);
This array has the values I'd like to combine together
$vals = array (
"0" => "830680",
"1" => "20",
"2" => "Sullivan Avenue",
"3" => "333000",
"4" => "12",
"5" => Array
(
"0" => "4",
"1" => "Maryland",
),
"6" => Array
(
"0" => "782",
"1" => "baltimore",
"2" => "Baltimore",
)
);
When I try to do array_combine($keys, $val);
I get 2 Notices about Array to string conversion
I guess array_combine only works on one dimensional arrays, any ideas on how to approach this?
If $keys was modified could it be combined with the values - problem is the shape of $keys is what I want to end up with?
It can be done recursively.
function combine_recursive($keys, $values) {
$result = array();
$key = reset($keys);
$value = reset($values);
do {
if (is_array($value)) {
$result[key($keys)] = combine_recursive($key, $value);
} else {
$result[key($keys)] = $value;
}
$value = next($values);
} while ($key = next($keys));
return $result;
}
This works for me with your example arrays. I'm sure this will give you all kinds of weird results/errors if the array structures are different from each other at all.