This question already has answers here:
Filter multidimensional array by value in array [duplicate]
(2 answers)
Closed 3 years ago.
I have an array like this:
$array = (
[0] => stdClass Object
(
[ID] => 420
[name] => Mary
)
[1] => stdClass Object
(
[ID] => 10957
[name] => Blah
)
)
...
I found some solution to search using loop like this:
$item = null;
foreach($array as $struct) {
if ($v == $struct->ID) {
$item = $struct;
break;
}
}
Because of the large amount of data, I want to change it so that I can retrieve multiple values instead of one value at a time (ex: $array->420 = Mary, $array->10957 = Blah,...). Which way would be the most optimal in this case?
If you index your main array by the ID (use array_column() for this), and an array of the ID's you are after, then array_intersect_key() will extract all of the ones you want into a list of the matches...
$array =[
(Object)
[
"ID" => 420,
"name" => "Mary"
],
(Object)
[
"ID" => 10957,
"name" => "Blah"
]
];
$ids = [420, 10957];
$indexArray = array_column($array, null, "ID" );
$matches = array_intersect_key($indexArray, array_flip($ids));
print_r($matches);
gives..
(
[420] => stdClass Object
(
[ID] => 420
[name] => Mary
)
[10957] => stdClass Object
(
[ID] => 10957
[name] => Blah
)
)
You need to use array_flip() on the ID's array to convert the value into the key to work with the array_intersect_key() function.
You can then use array_values() if you don't want the key for this data (i.e. the ID)
Here's three possible solutions depending on your needs, using array_column:
Build an ID => name array:
$result = array_column($array, 'name', 'ID');
Build an ID => entry array (if you have more stuff than just the name):
$result = array_column($items, null, 'ID');
Alternative using array_reduce:
$result = array_reduce($array, static function ($result, $item) {
$result[$item['ID']] = $item;
return $result;
});
Demo: https://3v4l.org/fLMgL
Related
I need to remove objects from a 3d array where the same two-property object is found in any other row.
I previously asked this similar question, but my new requirements are slightly different because I was keeping one of the encountered duplicates. Now I would like for both/all encountered duplicates to be removed.
[
[
["name" => "John", "surname" => "Smith"],
["name" => "Kate", "surname" => "Winston"]
],
[
["name" => "Kate", "surname" => "Winston"],
["name" => "Jack", "surname" => "Irving"]
],
]
Desired filtered result with same original structure:
[
[
["name" => "John", "surname" => "Smith"],
],
[
["name" => "Jack", "surname" => "Irving"]
],
]
Seems like others answers don't see their own final results and don't read desired output.
Here a little bit hard solution but it works well.
Note: the input data array must have 2 object indexes and 2 arrays of objects for comparing, otherwise, it should be fixed.
$ar = Array (
0 => [(object)["name"=>"John", "surname"=>"Smith"], (object)["name"=>"Kate", "surname"=>"Winston"]],
1 => [(object)["name"=>"Kate", "surname"=>"Winston"], (object)["name"=>"Jack", "surname"=>"Irving"]]
);
$arr = [];
$k = 0; // do `if statement` only once
foreach($ar as $num=>&$subar){
foreach($subar as $num2=>$pers){
$subar[$num2] = (array)$pers; // object to array
if (!$k) {
$keys = array_keys($subar[$num2]); // collect "name" and "surname" in an array
$k++;
}
foreach($subar[$num2] as $a=>$b){
$seq = array_search($a,$keys); // index of the current key
if (!$seq) { // 0 -> "name", 1 -> "surname"
$arr[$num][$b] = '';
} else {
$arr[$num][$subar[$num2][current($keys)]] = $b;
}
}
}
}
$diff[] = array_diff($arr[0],$arr[1]); // clear duplicates from 1-st set
$diff[] = array_diff($arr[1],$arr[0]); // clear duplicates from 2-nd set
Gives result:
Array
(
[0] => Array
(
[John] => Smith
)
[1] => Array
(
[Jack] => Irving
)
)
And after you can re-create the output array:
// creating a new array
$res = [];
foreach($diff as $num=>$ns){
foreach($ns as $name=>$surname){
foreach($keys as $ind=>$key){
if ($ind % 2 == 0){
$tmp[$key] = $name; // put name
} else {
$tmp[$key] = $surname; // put surname
}
}
$res[$num] = (object)$tmp; // array to object
}
}
Output will be:
Array
(
[0] => stdClass Object
(
[name] => John
[surname] => Smith
)
[1] => stdClass Object
(
[name] => Jack
[surname] => Irving
)
)
Demo
In case of string values in the input arrays, i.e.:
$ar = [
'[{"name":"John", "surname":"Smith"}, {"name":"Kate", "surname":"Winston"}]',
'[{"name":"Kate", "surname":"Winston"}, {"name":"Jack", "surname":"Irving"}]'
];
You need a little fix:
...
foreach($ar as $num=>&$subar){
$ar[$num] = json_decode($subar);
foreach($subar as $num2=>$pers){
...
The same output you will get.
Demo
It's easier if you don't trim away the brackets [], as you stated that you did in the comments. That way, they are proper JSON strings, which we can use in PHP.
Map (or loop) over your array, and build up a $result array, where you append all the arrays from your decoded JSON. Once you have your final $result, you have an array that looks somewhat like
Array (
[0] => Array
(
[name] => John
[surname] => Smith
)
[1] => Array
(
[name] => Kate
[surname] => Winston
)
[2] => Array
(
[name] => Kate
[surname] => Winston
)
[3] => Array
(
[name] => Jack
[surname] => Irving
)
)
We have all the values in an actual array now, but there are duplicates -- which can be removed using array_unique() with the SORT_REGULAR flag.
$array = [
'[{"name":"John", "surname":"Smith"}, {"name":"Kate", "surname":"Winston"}]',
'[{"name":"Kate", "surname":"Winston"}, {"name":"Jack", "surname":"Irving"}]'
];
$result = [];
array_map(function($v) use (&$result) {
$result = array_merge($result, json_decode($v, true));
}, $array);
print_r(array_unique($result, SORT_REGULAR));
Final output:
Array
(
[0] => Array
(
[name] => John
[surname] => Smith
)
[1] => Array
(
[name] => Kate
[surname] => Winston
)
[3] => Array
(
[name] => Jack
[surname] => Irving
)
)
Live demo at https://3v4l.org/q6pZc
$array = [
'[{"name":"John", "surname":"Smith"}, {"name":"Kate", "surname":"Winston"}]',
'[{"name":"Kate", "surname":"Winston"}, {"name":"Jack", "surname":"Irving"}]'
];
$resultArray = [];
foreach ($array as $item) {
$bufferArray = array_merge($resultArray, json_decode($item));
foreach ($bufferArray as $elements) {
$key = $elements->name . $elements->surname;
if (array_key_exists($key, $resultArray)) {
unset($resultArray[$key]);
} else {
$resultArray[$key] = $elements;
}
}
}
print_r($resultArray);
Output
Array
(
[KateWinston] => stdClass Object
(
[name] => Kate
[surname] => Winston
)
[JackIrving] => stdClass Object
(
[name] => Jack
[surname] => Irving
)
)
can rewrite this into more serious code )
To remove objects from each row where a given object exists any where in any other row, you can make iterates calls of array_udiff(). Inside the function, the first parameter should be the currently iterated row and the next/subsequent parameter(s) should all of the other rows in the entire array. The last parameter is the callback which compares whole objects to whole objects via PHP's performance-optimized algorithm.
My snippet below will not only handle your 2-row array, it will also handle arrays with 3 or more rows.
Code: (Demo)
$result = [];
foreach ($array as $i => $objs) {
$cache = $array[$i];
unset($array[$i]);
$params = [
$objs,
...$array,
fn($a, $b) => $a <=> $b
];
$result[] = array_udiff(...$params);
$array[$i] = $cache;
}
var_export($result);
To be clear, this snippet will work the same if the array of arrays of objects is an array of arrays of arrays.
I have the following code:
Array
(
[0] => Array
(
[id] => '157a',
[name] => '***',
)
[1] => Array
(
[id] => '158a',
[name] => '***',
)
Need to copy the numeric keys (0, 1) for the array values ('157a', '158a'):
Array
(
[157a] => Array
(
[id] => '157a',
[name] => '***',
)
[158a] => etc
What is the most efficient way to achieve this?
Pass null as the second parameter to array_column() to get the entire sub-array and pass id as the third to index the array by the values of that column:
$array = array_column($array, null, 'id');
Dont know if its the efficient way, but i would do something like this:
$newArray = [];
foreach($array as $v)
{
$newArray[$v['id']] = $v;
}
You can use array_column for that:
array_column($input, $item, 'id');
Or you can use array_reduce to do that in a functional programming way.
$changedArray = array_reduce($input, function ($result, $item) {
$result[$item['id']] = $item;
return $result;
}, array());
var_dump($changedArray);
I have 2 arrays:
Array
(
[0] => Array
(
[id] => 1
[fieldname] => banana
[value] => yellow
)
)
Array
(
[0] => Array
(
[id] => 1
[fieldname] => rome
[value] => city
)
[1] => Array
(
[id] => 2
[fieldname] => bla
[value] => yes
)
)
I want to create a new array that contains only elements where "id" is different. In other words I want to get this output:
Array
(
[0] => Array
(
[id] => 2
[fieldname] => bla
[value] => yes
)
)
[id] => 2 was the only different [id] so I keep it.
Said that I've already managed to achieve my goal with an inefficient pile of foreach, if statements and temp variables. I really don't want to use a wall of code for this very small thing so I started to look for a native PHP function with no success. What's the easiest way to get the result? Is it possible that I strictly need to use a foreach with so many if?
You can use array_udiff with a function.
Computes the difference of arrays by using a callback function for
data comparison.
Returns an array containing all the values of the first array that are not
present in any of the other arguments.
The code:
// Setup two arrays as per your question
$array1 = array (
'0' => array (
'id' => '1',
'fieldname' => 'banana',
'value' => 'yellow',
)
);
$array2 = array (
'0' => array (
'id' => '1',
'fieldname' => 'rome',
'value' => 'city',
),
'1' => array (
'id' => '2',
'fieldname' => 'bla',
'value' => 'yes',
)
);
// Setup the callback comparison function
function arrayCompare($array2, $array1) {
return $array2['id'] - $array1['id'];
}
// Use array_udiff() with the two arrays and the callback function
$arrayDiff = array_udiff($array2, $array1, 'arrayCompare');
print_r($arrayDiff);
The above code returns the following:
Array (
[1] => Array (
[id] => 2
[fieldname] => bla
[value] => yes
)
)
This should do it. Not super short and it does use a temporary variable, so perhaps not what you were looking for. I've named the two arrays one and two.
$ids = array();
$result = array();
foreach ($one as $x) {
$ids[$x['id']] = 1; //This way, isset($x['id']) vill return true
}
foreach ($two as $x) {
if (!isset($ids[$x['id']])) {
$result[] = $x;
}
}
I would be surprised if there wasn't an even more compact way to do it.
EDIT: This is an alternative variant with nested for each. Not particularly short either.
$result = array();
foreach ($one as $x) {
foreach ($two as $y) {
if ($x['id'] == $y['id']) {
//A match, lets try the next $x
continue 2;
}
}
//No matching id in $two
$result[] = $x;
}
I am trying to combine two arrays while respecting their shared value.
$array1 = array(
array("id" => "1","name"=>"John"),
array("id" => "2","name"=>"Peter"),
array("id" => "3","name"=>"Tom"),
array("id" => "12","name"=>"Astro")
);
$array2 = array(
array("id" => "1","second_name"=>"Lim"),
array("id" => "2","second_name"=>"Parker"),
array("id" => "3","second_name"=>"PHP")
);
My expected output:
$result = array(
array("id" => "1","name"=>"John","second_name"=>"Lim"),
array("id" => "2","name"=>"Peter","second_name"=>"Parker"),
array("id" => "3","name"=>"Tom","second_name"=>"PHP"),
array("id" => "12","name"=>"Astro")
);
I have made a try by
$arraycomb = array_unique(array_merge($array1,$array2), SORT_REGULAR);
My output is:
Array
(
[0] => Array
(
[id] => 1
[name] => John
)
[1] => Array
(
[id] => 2
[name] => Peter
)
[2] => Array
(
[id] => 3
[name] => Tom
)
[3] => Array
(
[id] => 12
[name] => Astro
)
[4] => Array
(
[id] => 1
[second_name] => Lim
)
[5] => Array
(
[id] => 2
[second_name] => Parker
)
[6] => Array
(
[id] => 3
[second_name] => PHP
)
)
How can I combine the key value inside same array? or how can I bring the expected output?
Note: I am trying for value instead of key ref: PHP Array Merge two Arrays on same key
Alternatively, you could use a foreach in this case then merge them if they share the same id key
With using reference &
foreach($array1 as &$value1) {
foreach ($array2 as $value2) {
if($value1['id'] == $value2['id']) {
$value1 = array_merge($value1, $value2);
}
}
}
echo '<pre>';
print_r($array1);
You can use array_map() for this. Try this -
function modifyArray($a, $b)
{
if (!empty($a) && !empty($b)) {
return array_merge($a, $b);
} else if (!empty($a) && empty($b)) {
return $a;
} else if (empty($a) && !empty($b)) {
return $b;
}
}
$new = array_map("modifyArray", $array1, $array2);
var_dump($new);
It will generate the new array will all the values in both arrays.if the first array's element is empty then the second array will be merged and vice-versa.
Assign temporary first level keys to your first array to aid in identifying rows. Then loop the second array and append the desired column value to the appropriate group. Re-index the array after looping with array_values().
Code: (Demo)
$result = array_column($array1, null, 'id');
foreach ($array2 as $row) {
$result[$row['id']]['second_name'] = $row['second_name'];
}
var_export(array_values($result));
This is a more direct approach than brute force scanning arrays with nested loops.
If all ids in the second array exist in the first array, then the following simpler line can be written inside the body of the foreach().
$result[$row['id']] += $row;
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to “flatten” a multi-dimensional array to simple one in PHP?
How to create an array of inner array values with array function ?
Here is array
Array
(
[0] => Array
(
[Detail] => Array
(
[detail_id] => 1
)
)
[1] => Array
(
[Detail] => Array
(
[detail_id] => 4
)
)
)
I want create an array with detail_id of above array i.e
array(1, 4)
Is it done any array function in PHP ?
There isn't any one function which can do this single-handed. array_map is the closest you'd get, but it doesn't really deal with the extra recursion level. Why don't you just use loops?
$new_array = array();
foreach($main_array as $key => $second_array)
{
foreach($second_array as $second_key => $third_array)
{
$new_array[] = $third_array['detail_id'];
}
}
echo implode(',',$new_array);
If your are looking for a one liner:
$val = array(
array('Detail' => array('detail_id' => 1)),
array('Detail' => array('detail_id' => 4)),
);
var_dump($val);
I am looking for answer like this
$result = array_map( function($a) {
return $a['Detail']['detail_id']; }, $mainArray
);
This works correct..