I have two arrays. One containing the data and other contains the keys. So I have
$data = array(
'name' => array('label' => 'Name:', 'value' => 'Genghis'),
'age' => array('label' => 'Age:', 'value' => '67'),
'weigh' => array('label' => 'Weigh in Kgs:', 'value' => '78')
);
and
$keys = array('name', 'age');
Now I want to extract only the name and age elements of $data. Some thing like this.
$extracted = somemethod($data, $keys);
var_export($extracted);
Output should be like this.
array(
'name' => array(
'label' => 'Name:',
'value' => 'Genghis',
),
'age' => array(
'label' => 'Age:',
'value' => '67',
),
)
How can i do this?
I would use an array_intersect_key() function like this:
$data = array(...); // initial array as described
$retained_keys = array('name' => 'value not used', 'age' => 'value not used');
$filtered_array = array_intersect_key($data, $retained_keys);
Loop over the keys, grab the array values, and return them:
function somemethod($data, $keys) {
$return = array();
foreach( $keys as $k) {
$return[$k] = isset( $data[$k]) ? $data[$k] : null;
}
return $return;
}
The above adds 'null' when a field isn't found. You can modify the foreach loop to just skip the key when it's not found in the $data array, like this:
function somemethod($data, $keys) {
$return = array();
foreach( $keys as $k) {
if( isset( $data[$k])) {
$return[$k] = $data[$k];
}
}
return $return;
}
Edit: To extend on Mike Brant's answer, array_intersect_key() can be used with array_flip() in a function to achieve the desired output:
function somemethod($data, $keys) {
$keys = array_flip( $keys);
return array_intersect_key($data, $keys);
}
Yes, it uses array_flip(), but the original $keys array is left unmodified, as a copy of that array is what gets flipped. So, you would still call this function with:
$extracted = somemethod( $data, array('name', 'age'));
Not exactly onerous to write
$extracted = array();
foreach($keys as $key) {
if (isset($data[$key]))
$extracted[$key] = $data[$key];
}
Related
I have main array:
$main = array(
'city' => 'London',
'street' => 'Hyde Park',
'name' => 'John'
);
And examples:
$example1 = array(
'city',
'name'
);
$example2 = array(
'city',
'street',
'name'
);
I would like to receive (by single array):
$example1 = array(
'London',
'John'
);
$example2 = array(
'London',
'Hyde Park',
'John'
);
Is better way for this than:
function newArray($mainArray, $array) {
$new_array = [];
foreach ($mainArray as $key => $main) {
if (in_array($main, $array)) {
$new_array = $key;
}
}
return $new_array;
}
?
Maybe I can use array_map or array_walk, but how?
As you suggested, array_map is good for this.
$example1Mapped = array_map(function($key) use ($main) {
return array_key_exists($key, $main) ? $main[$key] : $key;
}, $example1);
$example2Mapped = array_map(function($key) use ($main) {
return array_key_exists($key, $main) ? $main[$key] : $key;
}, $example2);
Another approach could be to use a combination of array_flip and array_intersect_key
$example1Mapped = array_intersect_key($main, array_flip($example1));
array_flip will turn the values of an array into keys and its key into the values. So $example1 = ['city', 'name']; will be turned into $example1 = ['city' => 0, 'name' => 1];
array_intersect_key then will remove all values from $main, which keys are not present in the flipped $example1.
Yet this solution will not keep the order of the values, but instead enforce the order of the $main array.
If there are values in your example arrays, that are not present as keys in the $main array the values will be kept in the array_map approach, while they will be removed in the second approach.
I have an array like:
$array = array(
'name' => 'Humphrey',
'email' => 'humphrey#wilkins.com
);
This is retrieved through a function that gets from the database. If there is more than one result retrieved, it looks like:
$array = array(
[0] => array(
'name' => 'Humphrey1',
'email' => 'humphrey1#wilkins.com'
),
[1] => array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
)
);
If the second is returned, I can do a simple foreach($array as $key => $person), but if there is only one result returned (the first example), I can't run a foreach on this as I need to access like: $person['name'] within the foreach loop.
Is there any way to make the one result believe its a multidimensional array?
Try this :
if(!is_array($array[0])) {
$new_array[] = $array;
$array = $new_array;
}
I would highly recommended making your data's structure the same regardless of how many elements are returned. It will help log terms and this will have to be done anywhere that function is called which seems like a waste.
You can check if a key exists and do some logic based on that condition.
if(array_key_exists("name", $array){
//There is one result
$array['name']; //...
} else {
//More then one
foreach($array as $k => $v){
//Do logic
}
}
You will have the keys in the first instance in the second yours keys would be the index.
Based on this, try:
function isAssoc(array $arr)
{
if (array() === $arr) return false;
return array_keys($arr) !== range(0, count($arr) - 1);
}
if(isAssoc($array)){
$array[] = $array;
}
First check if the array key 'name' exists in the given array.
If it does, then it isn't a multi-dimensional array.
Here's how you can make it multi-dimensional:
if(array_key_exists("name",$array))
{
$array = array($array);
}
Now you can loop through the array assuming it's a multidimensional array.
foreach($array as $key => $person)
{
$name = $person['name'];
echo $name;
}
The reason of this is probably because you use either fetch() or fetchAll() on your db. Anyway there are solutions that uses some tricks like:
$arr = !is_array($arr[0]) ? $arr : $arr[0];
or
is_array($arr[0]) && ($arr = $arr[0]);
but there is other option with array_walk_recursive()
$array = array(
array(
'name' => 'Humphrey1',
'email' => 'humphrey1#wilkins.com'
),
array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
)
);
$array2 = array(
'name' => 'Humphrey2',
'email' => 'humphrey2#wilkins.com'
);
$print = function ($item, $key) {
echo $key . $item .'<br>';
};
array_walk_recursive($array, $print);
array_walk_recursive($array2, $print);
I need elements of array 1 that are not present in array 2 based on the 'value' key only.
Array1
$array1 = array(
array('value' => 113214, 'revision_id' => 2047152),
array('value' => 236462, 'revision_id' => 2045678),
array('value' => 236541, 'revision_id' => 2047155)
);
Array2
$array2 = array(
array('value' => 113214, 'revision_id' => 2047152),
array('value' => 236461, 'revision_id' => 2047153),
array('value' => 236541, 'revision_id' => 2047155)
);
I need the output as below, the difference of arrays should be based on Value
$output = array(
array('value' => 236462, 'revision_id' => 2045678)
);
Just do a nested foreach loop and check the condition hope its helps you :
$arraycheck= array();
foreach($newData as $data1) {
$duplicatecheck = false;
foreach($oldData as $data2) {
if($data1['value'] === $data2['value'] && $data1['revision_id'] === $data2['revision_id']) $duplicatecheck = true;
}
if($duplicatecheck === false) $arraycheck[] = $data1;
}
First, use array_column to get the values of 'value' from array2 into a one-dimensional array:
$a2values = array_column($array2, 'value');
Then use those values to array_filter array1.
$result = array_filter($array1, function($item) use ($a2values) {
// only keep items with values not in array2
return !in_array($item['value'], $a2values);
});
You can use array_udiff which accepts last parameter as callback, and you can define your comparison there easily.
$array1 = [
['value' => '113214', 'revision_id' => '2047152'],
['value' => '236462', 'revision_id' => '2045678'],
['value' => '236541', 'revision_id' => '2047155'],
];
$array2 = [
['value' => '113214', 'revision_id' => '2047152'],
['value' => '236461', 'revision_id' => '2047153'],
['value' => '236541', 'revision_id' => '2047155'],
];
$result = array_udiff ($array1, $array2, function($x, $y) {
return $x['value'] - $y['value'];
});
print_r($result);
taken from: https://gist.github.com/wrey75/c631f6fe9c975354aec7
function my_array_diff($arr1, $arr2) {
$diff = array();
// Check the similarities
foreach( $arr1 as $k1=>$v1 ){
if( isset( $arr2[$k1]) ){
$v2 = $arr2[$k1];
if( is_array($v1) && is_array($v2) ){
// 2 arrays: just go further...
// .. and explain it's an update!
$changes = self::diff($v1, $v2);
if( count($changes) > 0 ){
// If we have no change, simply ignore
$diff[$k1] = array('upd' => $changes);
}
unset($arr2[$k1]); // don't forget
}
else if( $v2 === $v1 ){
// unset the value on the second array
// for the "surplus"
unset( $arr2[$k1] );
}
else {
// Don't mind if arrays or not.
$diff[$k1] = array( 'old' => $v1, 'new'=>$v2 );
unset( $arr2[$k1] );
}
}
else {
// remove information
$diff[$k1] = array( 'old' => $v1 );
}
}
// Now, check for new stuff in $arr2
foreach( $arr2 as $k=>$v ){
// OK, it is quite stupid my friend
$diff[$k] = array( 'new' => $v );
}
return $diff;
}
usage:
$diff = my_array_diff($arr1, $arr2);
var_dump($diff);
I have a PHP array like this:
$arr = array(
'id' => 'app.settings.value.id',
'title' => 'app.settings.value.title',
'user' => 'app.settings.value.user'
);
I want to remove '.id', '.title' and '.user' in the array values. I want to insert the key of this array at the end of the value. I know, that I can get an array key by passing an array and a value to 'array_search', but I want the key within this one array definition - at the end of it's value. Is this possible?
I don't like this, but I guess it's simple and works:
$arr = array(
'id' => 'app.settings.value',
'title' => 'app.settings.value',
'user' => 'app.settings.value'
);
$result = array();
foreach ($arr AS $key => $value) {
$result[$key] = $value . '.' . $key;
}
You're storing app.settings.value which is the same for all array items, so personally I'd prefer:
$arr = array(
'id',
'title',
'user'
);
function prepend_key($key)
{
return 'app.settings.value.' . $key;
}
$result = array_map('prepend_key', $arr);
With $result containing:
array(
'app.settings.value.id',
'app.settings.value.title',
'app.settings.value.user'
);
At the end of the day, either works :)
I was wondering when working with multimedional arrays, if a certain key is the same, is there a way to combine the contents of other keys into its own array if a certain key is the same?
Something like this:
// name is the same in both arrays
array(
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '1234567'
),
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '5556734'
)
)
into something like this
array(
array(
'name' => 'Pepsi',
'store' => array('Over here', 'Over here'),
'number' => array('1234567', '5556734')
)
)
The defining key is checking if the name element is the same for the other arrays.
You can try a function like this.
function mergeByKey($array,$key){
$tmp_array = array();
foreach ( $array as $k => $row ) {
$merged = false;
foreach ($tmp_array as $k2 => $tmp_row){
if ($row[$key] == $tmp_row[$key]){
foreach ( $row as $k3 => $value ) {
if ($k3 == $key) continue;
$tmp_array[$k2][$k3][] = $value;
$merged = true;
}
}
if ($merged) break;
}
if (!$merged) {
$new_row = array();
foreach ( $row as $k4 => $value ) {
if ($k4 == $key) $new_row[$k4] = $value;
else $new_row[$k4] = array($value);
}
$tmp_array[] = $new_row;
}
}
foreach ( $tmp_array as $t => $row ) {
foreach ( $row as $t2 => $value ) {
if ( count($value) == 1 && $t2 != $key ) $tmp_array[$t][$t2] = $value[0];
}
}
return $tmp_array;
}
passing the array as first parameter and the key as second one.
I'm referencing to your array structure
edited: missed a piece
edited2: if resultin array contains elements with one string, it returns a string and not a array with one element
demo
This function uses a given field name as the grouping identifier and turns all other fields into arrays.
Note that single occurrences of your field name will yield arrays with a single element for the other fields. I wasn't sure whether that's a desirable trait, but just making sure you know ;-)
$arr = array(
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '1234567'
),
array(
'name' => 'Pepsi',
'store' => 'Over here',
'number' => '5556734'
)
);
function mergeArray($array, $column)
{
$res = array();
foreach ($array as $item) {
foreach ($item as $key => $value) {
if ($key === $column) {
$res[$column][$key] = $value;
} else {
$res[$column][$key][] = $value;
}
}
}
return array_values($res);
}
print_r(mergeArray($arr, 'name'));
Demo
Thanks to Gianni Lovece for her answer but I was able to develop a much simpler solution based on this problem. Just plug in the $result_arr to browse through and the $key you want to use as basis and it immediately outputs a multidimensional array with non-repeating values for repeating elements (see example below).
function multiarray_merge($result_arr, $key){
foreach($result_arr as $val){
$item = $val[$key];
foreach($val as $k=>$v){
$arr[$item][$k][] = $v;
}
}
// Combine unique entries into a single array
// and non-unique entries into a single element
foreach($arr as $key=>$val){
foreach($val as $k=>$v){
$field = array_unique($v);
if(count($field) == 1){
$field = array_values($field);
$field = $field[0];
$arr[$key][$k] = $field;
} else {
$arr[$key][$k] = $field;
}
}
}
return $arr;
}
For example, in the sample array for this question, running multiarray_merge($mysample, 'name') returns
array(
'Pepsi' => array(
'name' => 'Pepsi',
'store' => 'Over here', // String: Not an array since values are not unique
'number' => array('1234567', '5556734') // Array: Saved as array since values are unique
)
);