How to add subvalues to a new array? [duplicate] - php

This question already has answers here:
Is there a function to extract a 'column' from an array in PHP?
(15 answers)
Closed 5 months ago.
I have an array with every containing value being another array with one value. I was looking for a way to flatten the array and succeeded but somehow I am having this feeling that it can be done better. Is this the best way or can it still be improved?
<?php
$array = array(
'1' => array('id' => '123'),
'2' => array('id' => '22'),
'3' => array('id' => '133'),
'4' => array('id' => '143'),
'5' => array('id' => '153'),
);
array_walk_recursive($array, function($v, $k) use (&$result) {
$result[] = $v;
});

You can achieve that using the array_map function:
$func = function($value) {
return $value['id'];
};
$array2 = array_map($func, $array);
Or if you want to keep it in one line do:
$array2 = array_map(function($value) { return $value['id']; }, $array);
This will return the array flattened and keeps your initial keys:
array(5) {
[1]=>
string(3) "123"
[2]=>
string(2) "22"
[3]=>
string(3) "133"
[4]=>
string(3) "143"
[5]=>
string(3) "153"
}
If you don't want to keep the keys, then call the following at the end:
$array2 = array_values($array2);

You can use array_map() passing null as the first argument while unpacking the passed array with the splat operator and grab the first element of the result:
$result = array_map(null, ...$array)[0];
Another option would be to use array_column() which creates an array from a single column of a given multidimensional array - feed it your array and column key, e.g.:
$result = array_column($array, 'id');
Output for either:
print_r($result);
Array
(
[0] => 123
[1] => 22
[2] => 133
[3] => 143
[4] => 153
)

This is what I would do. Its cleaner:
$array = array(
'1' => array('id' => '123'),
'2' => array('id' => '22'),
'3' => array('id' => '133'),
'4' => array('id' => '143'),
'5' => array('id' => '153'),
);
foreach($array as $key => $arr){
$result[] = $arr['id'];
}

If the depth won't ever change a foreach loop would likely be faster. That anonymous function has some overhead to it and it really shows the longer your array gets.
If the depth is variable as well, however, then this is the fastest way to traverse and flatten.

Related

Split an array into two arrays based on identical values

I have this array:
$arrayAll = [
'156' => '1',
'157' => '1',
'158' => '2',
'159' => '1',
'160' => '2',
'161' => '1'
];
where the keys are unique - they don't ever repeat. And the value could be either 1 or 2 - nothing else.
And I need to "split" this $arrayAll array into $array1 - that will contain everything with value 1 and $array2 - that will contain everything with value 2 so in the end I will have:
$array1 = [
'156' => '1',
'157' => '1',
'159' => '1',
'161' => '1'
];
and
$array2 = [
'158' => '2',
'160' => '2'
];
and as you can see, I will have the keys from the original array will remain the same.
What is the simplest thing to do to separate the original array like this?
This is probably the simplest way.
Loop it and create a temporary array to hold the values then extract the values to your array 1 and 2.
Foreach($arrayAll as $k => $v){
$res["array" . $v][$k] = $v;
}
Extract($res);
Var_dump($array1, $array2);
https://3v4l.org/6en6l
Updated to use extract and a method of variable variables.
The update means it will work even if there is a value "3" in the input array.
https://3v4l.org/jbvBf
Use foreach and compare each value and assign it to a new array.
$array1 = [];
$array2 = [];
foreach($arrayAll as $key=>$val){
if($val == 2){
$array2[$key] = $val;
}else{
$array1[$key] = $val;
}
}
print_r($array1);
print_r($array2);
Demo
The simplest thing to do is to use a foreach loop.
$array = [
'156' => '1',
'157' => '1',
'158' => '2',
'159' => '1',
'160' => '2',
'161' => '1'
];
$array1 = [];
$array2 = [];
foreach ($array as $key => $value)
// If value is 1, add to array1
// If value is not 1, add value to array2
if ($value === '1')
$array1[$key] = $value;
else
$array2[$key] = $value;
echo var_dump($array1);
echo '<br>';
echo var_dump($array2);
Use indirect reference:
$arrayAll = array("156"=>"1", "157"=>"1", "158"=>"2", "159"=>"1", "160"=>"2", "161"=>"1");
foreach($arrayAll as $key=>$value) {
$name = "array".$value;
$$name[$key] = $value;
}
echo "<pre>";
print_r($array1);
print_r($array2);
echo "</pre>";
//your array
$yourArray = [
'156' => '1',
'157' => '1',
'158' => '2',
'159' => '1',
'160' => '2',
'161' => '1'
];
With the conditions you mentioned just build two arrays, you can use array_keys with the second parameter that accepts a search value
$array1 = array_keys($yourArray, '1');
$array2 = array_keys($yourArray, '2');
If you don't want to use array_keys, go for an iteration
$array1 = array();
$array2 = array();
foreach($yourArray as $key=>$value){
//will always be 1 or 2, so an if-else is enought
if($value == 1){
$array1[] = $key;
} else {
$array2[] = $key;
}
}
And that's it.
Check this link for array_keys
If you have more than 2 values, the following will work and can be reused for other cases
You want to group them according to the values
$arrayOfValues = array_values($yourArray);
//this returns only the values of the array
$arrayOfUniqueValues = array_unique($arrayOfValues);
//this returns an array with the unique values, also with this u consider
//the posibility for more different values
//also u can get the unique values array on a single line
$arrayIfUniqueValues = array_unique(array_values($yourArray));
The array you will return
$theReturn = array();
foreach($arrayOfUniqueValues as $value ){
//what does this do?
//for each iteration it creates a key in your return array "$theReturn"
//and that one is always equal to the $value of one of the "Unique Values"
//array_keys return the keys of an array, and with the second parameter
//it acceps a search parameter, so the keys it return are the ones
//that matches the value, so here u are getting the array already made
$theReturn[$value] = array_keys($yourArray, $value);
}
The var_dump, in this case, will look like this
array(2) {
[1]=>
array(4) {
[0]=>
int(156)
[1]=>
int(157)
[2]=>
int(159)
[3]=>
int(161)
}
[2]=>
array(2) {
[0]=>
int(158)
[1]=>
int(160)
}
}
Hope my answer helps you, I tried to organize the solutions starting with the shortest/simplest.
Edit:
I forgot you needed the key value too, at least in this solution the array is always referring to the value, like $array1, $array2 or the $key references to the value as in the last solution
The simplest solution for separating an array into others based on the values involves:
Getting its unique values using array_unique.
Looping over these values using foreach.
Getting the key-value pairs intersecting with the current value using array_intersect.
Code:
# Iterate over every value and intersect it with the original array.
foreach(array_unique($arrayAll) as $v) ${"array$v"} = array_intersect($arrayAll, [$v]);
Advantage:
The advantage of this answer when compared to other given answers is the fact that it uses array_unique to find the unique values and therefore iterates only twice instead of n times.
Check out a live demo here.

Array comparision in php to get only difference

Following Below are two arrays which i wanna compare and remove the same values something like array_diff() Function and i want to store the result in third array
$array1 = Array([0] => Array([a] => XYZ,[b] => ABC))
$array2 = Array([0] => Array([a] => XYZ,[b] => ABC),[1] => Array([a] => PQR,[b] => XYZ))
$array3 = array_diff($array1,$array2);
//$array3 value must return this value Array([1] => Array[a]=> PQR,[b] => XYZ)
I don't know what i am doing wrong but i am getting error that array cannot be converted into string. Can anyone help me with this?
Thanks in advance
If you are sure that your $array2 will always contain more elements than $array1 then here is your solution:
$array1 = array(array('a' => 'XYZ','b' => 'ABC'));
$array2 = array(array('a' => 'XYZ','b' => 'ABC'),array('a' => 'PQR','b' => 'XYZ'));
$limit = count($array2);
$array3 = array();
for($i=0;$i<$limit;$i++){
if(empty($array1[$i]))
$array3[] = $array2[$i];
$array3[] = array_diff($array1[$i],$array2[$i]);
}
foreach($array3 as $k=>$a3){
if(empty($a3)||($a3===NULL))
continue;
$result[$k] = $a3;
}
var_dump($result); //array(1) { [1]=> array(2) { ["a"]=> string(3) "PQR" ["b"]=> string(3) "XYZ" } }
Please note that array_diff works on 1D array and you was providing 2D arrays as parameter and that's why it wasn't working.
Also your way of defining $array1 and $array2 is wrong, please check this solution for right syntax.
I hope it helps

Sorting two associative arrays based on different keys

I have the following two associative arrays:
$arr1 = array(
'id' => 1,
'text' => 'Some text is here',
'timestamp' => 130458750
)
$arr2 = array(
'post_id' => 12,
'content' => 'Some content is here too',
'created_at' => 1402154823
)
I want to sort these two arrays based on timestamp and created_at keys, i.e. the larger integer is first and lesser second and so on. Is that possible using PHP's built-in functions? If not, how may I approach the problem?
EDIT
The desired result is: Here, $arr1's timestamp is less and $arr2's timestamp (i.e. created_at) is larger. So, I want to get a combination of $arr1 and $arr2 where $arr2 is first and $arr1 is second. Something like:
$sorted_arr = array($arr2, $arr1);
First let me say that one of your array contains timestamp and second contains created_at. I assumed both of them should be created_at.
In case you want to "sort" just two entries like you said in the comments, the task is straightforward:
<?php
$arr1 = array(
'id' => 1,
'text' => 'Some text is here',
'created_at' => 130458750 #corrected from "timestamp"
);
$arr2 = array(
'post_id' => 12,
'content' => 'Some content is here too',
'created_at' => 1402154823
);
$posts = $arr2['created_at'] > $arr1['created_at']
? [$arr2, $arr1]
: [$arr1, $arr2];
But apparently what you're after is a way to sort the posts if they're in array of unknown length. In that case you should use uasort built-in PHP function, which allows to sort by user-defined function and maintains indexes in associative arrays (as opposed to plain usort). Example code would then look like this:
$posts = [$arr1, $arr2];
uasort($posts, function($a, $b)
{
return $b['created_at'] - $a['created_at'];
});
var_dump($posts);
which outputs:
array(2) {
[1]=>
array(3) {
["post_id"]=>
int(12)
["content"]=>
string(24) "Some content is here too"
["created_at"]=>
int(1402154823)
}
[0]=>
array(3) {
["id"]=>
int(1)
["text"]=>
string(17) "Some text is here"
["created_at"]=>
int(130458750)
}
}
To get reverse order you may just reverse arguments in custom sort function, i.e. swap $a with $b.
Combining rr-'s solution, I came up with the following:
$arr1 = array(
'id' => 1,
'text' => 'Some text is here',
'timestamp' => 130458750
);
$arr2 = array(
'post_id' => 12,
'content' => 'Some content is here too',
'created_at' => 1402154823
);
$arr3 = array(
'post_id' => 21,
'content' => 'Some content is here too',
'created_at' => 1258475
);
$arr = [];
$arr[] = $arr1;
$arr[] = $arr2;
$arr[] = $arr3;
uasort($arr, function($a, $b)
{
$t1 = isset($a['timestamp']) ? $a['timestamp'] : $a['created_at'];
$t2 = isset($b['timestamp']) ? $b['timestamp'] : $b['created_at'];
return $t2 - $t1
});
var_dump($arr);
It sorts the arrays even when the keys are different.

PHP select array element by ["something_*"]

I was wondering about this kind of situation.
What if i have a huge array say about 50k items or more.
Now let's say many of that array keys have prefix let's name it settings_, now if i want to select all values where key begins by settings_ would i need to loop trough all 50k items or is there a better way?
And say there is some "magical" way to do this with single level arrays, what about multidimensional ones?
There is preg_grep, which matches array values. Since you want to search keys, you need to invert keys and values with array_flip:
<?php
$array = array(
'armenia' => 0,
'argentina' => 1,
'brazil' => 2,
'bolivia' => 3,
'congo' => 4,
'denmark' => 5
);
$filtered = array_flip(preg_grep('/^b/', array_flip($array)));
var_dump($filtered);
/*
Output:
array(2) {
["brazil"]=>
int(2)
["bolivia"]=>
int(3)
}
*/
$arr_main_array = array('something_test' => 123, 'other_test' => 456, 'something_result' => 789);
foreach($arr_main_array as $key => $value){
$exp_key = explode('_', $key);
if($exp_key[0] == 'something'){
$arr_result[] = $value;
}
}
if(isset($arr_result)){
print_r($arr_result);
}
You can execute the code at
http://sandbox.onlinephpfunctions.com/code/884816dd115b3ccc610e1732e9716471a7b29b0f

Moving array element to top in PHP

$arr = array(
'a1'=>'1',
'a2'=>'2'
);
I need to move the a2 to the top, as well as keep the a2 as a key how would I go on about it I can't seem to think a way without messing something up :)
Here is a solution which works correctly both with numeric and string keys:
function move_to_top(&$array, $key) {
$temp = array($key => $array[$key]);
unset($array[$key]);
$array = $temp + $array;
}
It works because arrays in PHP are ordered maps.
Btw, to move an item to bottom use:
function move_to_bottom(&$array, $key) {
$value = $array[$key];
unset($array[$key]);
$array[$key] = $value;
}
You can achieve that this way:
$arr = array(
'a1'=>'1',
'a2'=>'2'
);
end($arr);
$last_key = key($arr);
$last_value = array_pop($arr);
$arr = array_merge(array($last_key => $last_value), $arr);
/*
print_r($arr);
will output (this is tested):
Array ( [a2] => 2 [a1] => 1 )
*/
try this:
$key = 'a3';
$arr = [
'a1' => '1',
'a2' => '2',
'a3' => '3',
'a4' => '4',
'a5' => '5',
'a6' => '6'
];
if (isset($arr[ $key ]))
$arr = [ $key => $arr[ $key ] ] + $arr;
result:
array(
'a3' => '3',
'a1' => '1',
'a2' => '2',
'a4' => '4',
'a5' => '5',
'a6' => '6'
)
Here's a simple one liner to get this done with array_splice() and the union operator:
$arr = array('a1'=>'1', 'a2'=>'2', 'a3' => '3');
$arr = array_splice($arr,array_search('a2',array_keys($arr)),1) + $arr;
Edit:
In retrospect I'm not sure why I wouldn't just do this:
$arr = array('a2' => $arr['a2']) + $arr;
Cleaner, easier and probably faster.
You can also look at array_multisort This lets you use one array to sort another. This could, for example, allow you to externalize a hard-coded ordering of values into a config file.
<?php
$ar1 = array(10, 100, 100, 0);
$ar2 = array(1, 3, 2, 4);
array_multisort($ar1, $ar2);
var_dump($ar1);
var_dump($ar2);
?>
In this example, after sorting, the first array will contain 0, 10, 100, 100. The second array will contain 4, 1, 2, 3. The entries in the second array corresponding to the identical entries in the first array (100 and 100) were sorted as well.
Outputs:
array(4) {
[0]=> int(0)
[1]=> int(10)
[2]=> int(100)
[3]=> int(100)
}
array(4) {
[0]=> int(4)
[1]=> int(1)
[2]=> int(2)
[3]=> int(3)
}

Categories