I have this array:
params {
[0] => {
name => "xxx"
value => "yyy"
}
[1] => {
name => "uuu"
value => "vvv"
}
}
and I want to achieve this:
params {
[0] => {
xxx => "yyy"
}
[1] => {
uuu => "vvv"
}
}
I can do it this way:
foreach ($params as &$param) {
$param[$param['name']] = $param['value'];
unset($param['name']);
unset($param['value']);
unset($param);
}
But I am wondering if this could be done on more elegant way?
This calls for an array mapping of values:
$params = array_map(function ($i) { return [$i['name'] => $i['value']]; }, $params);
You can use array_map to reiterate the array.
$params = [
[
'name' => "xxx",
'value' => "yyy"
],
[
'name' => "uuu",
'value' => "vvv"
]
];
$params = array_map(function($o){
return [ $o['name'] => $o['value'] ];
}, $params);
echo "<pre>";
print_r( $params );
echo "</pre>";
This will result to:
Array
(
[0] => Array
(
[xxx] => yyy
)
[1] => Array
(
[uuu] => vvv
)
)
Doc: array_map()
This is a bit shorter. By not using foreach you can directly replace the elements.
for ($i = 0; $i < count ($params); $i++)
$params[$i] = array ($params[$i]['name'] => $params[$i]['value']);
To make your current code a little bit more elegant, you could pass multiple arguments to unset
foreach ($params as &$param) {
$param[$param['name']] = $param['value'];
unset($param['name'], $param['value'], $param);
}
Try this :
foreach ($params as $key => $sub_array) {
// unset original array data
unset($params[$key]);
// construct the new values
$params[$key][$sub_array['name']] = $sub_array['value'];
}
EDIT:
Another approach more elegant is the following :
foreach($params as $k=>$s){
$params[$k]=array($s['name']=>$s['value']);
}
Please try this:
foreach ($params as $k => $v)
{
$nary[$v[name]] = $v[value];
}
$params = $nary;
Related
For four days I am trying to figure out how to solve this, as well as googling it, and was no luck
The problem is that I needed to loop through a nested array (for unknown deep) and keep the top-level keys (as a prefix to the last value) as long as I am still going deep, and then start over (the prefix need to reset) once it started a new path.
I want to generate complete addresses from this array.
$arr = [
"buildings" => [
"group1" => [
"b1" => [1,2,3,4],
"b2" => [1,2,3]
],
"group2" => [
"b1" => [1,2]
]
],
"villas" =>[
"group1" => [
"v1" => [1,2],
"v2" => [1]
],
"group2" => [
"v1" => [1],
"v2" => [1]
],
"group3" => [
"v1" => [1]
],
]
];
This is the needed output
buildings/group1/b1/1
buildings/group1/b1/2
buildings/group1/b1/3
buildings/group1/b1/4
buildings/group1/b2/1
buildings/group1/b2/2
buildings/group1/b2/3
buildings/group2/b1/1
buildings/group2/b1/2
villas/group1/v1/1
villas/group1/v1/2
villas/group1/v2/1
villas/group2/v1/1
villas/group2/v2/1
villas/group3/v1/1
I tried this function but also it didn't bring the wanted results
function test($array, $path = ""){
foreach ($array as $key => $value) {
if (is_array($value)){
$path .= $key."/";
test($value, $path);
} else {
echo $path.$value."<br>";
}
}
}
test($arr);
UPDATE
I understood where was my mistake and I wanted to share with you my modification to my method after I fixed it.
function test($array, $path = ""){
foreach ($array as $key => $value) {
if (is_array($value)){
test($value, $path . $key . '/');
} else {
echo $path.$value."<br>";
}
}
}
And thanks to #Kai Steinke he's method is way better than mine, and here is some improvements just to make it look better.
function flatten(array $array, array $flattened = [], string $prefix = ''): array
{
foreach ($array as $key => $value) {
if (is_array($value)) {
$flattened = array_merge( flatten($value, $flattened, $prefix . $key . '/'));
continue;
}
$flattened[] = $prefix . $value;
}
return $flattened;
}
Here you go:
function flatten($arr, $prefix = '') {
$result = [];
foreach ($arr as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, flatten($value, $prefix . $key . '/'));
} else {
$result[] = $prefix . $value;
}
}
return $result;
}
// Usage
print_r(flatten($arr))
Returns an Array:
Array (
[0] => buildings/group1/b1/1
[1] => buildings/group1/b1/2
[2] => buildings/group1/b1/3
[3] => buildings/group1/b1/4
[4] => buildings/group1/b2/1
[5] => buildings/group1/b2/2
[6] => buildings/group1/b2/3
[7] => buildings/group2/b1/1
[8] => buildings/group2/b1/2
[9] => villas/group1/v1/1
[10] => villas/group1/v1/2
[11] => villas/group1/v2/1
[12] => villas/group2/v1/1
[13] => villas/group2/v2/1
[14] => villas/group3/v1/1
)
Build and preserve the path using all encountered keys until arriving at a deep non-array value, then append the value to the string, and push the full path into the result array.
Code: (Demo)
function flatten(array $array, string $path = ''): array
{
$result = [];
foreach ($array as $k => $v) {
array_push(
$result,
...(is_array($v) ? flatten($v, "$path$k/") : ["$path$v"])
);
}
return $result;
}
var_export(flatten($array));
A slightly related answer where a slash-delimited string was built as the hierarchical path to a search value.
I am using Spout Excel reader to read Excel files from php code and saving into a multidimensional array in PHP variable,Array looks like this
$array = [
[
'id[0]' => 'BX-78',
'Name[0]' => 'XXX',
'Address[0]' => 'YUUSATD'
],
[
'id[1]' => 'BX-79',
'Name[1]' => 'YYY',
'Address[1]' => 'DHJSHDJGY'
],
[
'id[2]' => 'BX-80',
'Name[2]' => 'ZZZ',
'Address[2]' => 'DDSDSDA'
]
[
'id[3]' => 'BX-78',
'Name[3]' => 'AAA',
'Address[3]' => 'FSDSDS'
][
'id[4]' => 'BX-81',
'Name[4]' => 'XXX',
'Address[4]' => 'DSDSDSD'
]];
Now i want to show duplicate data from above array using two keys ['id'] and ['name'] if id repeats show as duplicate data,
If name repeats show that row as duplicate data if both are duplicate show as again duplicate row
Otherwise it is unique row.
I have tried using multidimensional array sorting but it is using only one key to match data in rows.
foreach ($arrExcelData as $v) {
if (isset($arrExcelData[$v[0]])) {
// found duplicate
continue;
}
// remember unique item
$arrExcelData3[$v[0]] = $v;
}
// if you need a zero-based array, otheriwse work with $_data
$arrExcelData2 = array_values($arrExcelData3);
Edited : Expected Output Result :
Matching Rows:
Id Name Address
-------------------------
BX-78 XXX YUUSATD
BX-78 AAA DDSDSDA
BX-81 XXX DSDSDSD`
If you want to list the duplicate values, I think the address of the second match should be FSDSDS as there is not item with name AAA and value DDSDSDA:
BX-78 AAA FSDSDS
If that is the case, what you could do is to first use a double foreach to mark the arrays that contain a duplicate id or name by for example adding a property named id and name except when the array is itself in the second loop.
After this loop, you can tell which arrays are the duplicate ones. Instead of using a corresponding index 0 as in id[0], I have used reset and next so it is not tied to these indexes.
To get the filtered result you could use array_reduce to check for the array keys and unset them.
For example:
foreach ($array as $index => $a) {
foreach ($array as $v) {
if ($v === $a) continue;
if (reset($v) === reset($a)) $array[$index]["id"] = "duplicate";
if (next($v) === next($a)) $array[$index]["name"] = "duplicate";
}
}
$array = array_reduce($array, function($carry, $item) {
if (array_key_exists("id", $item) || array_key_exists("name", $item)) {
unset($item["id"], $item["name"]);
$carry[] = $item;
}
return $carry;
}, []);
print_r($array);
Result
Array
(
[0] => Array
(
[id[0]] => BX-78
[Name[0]] => XXX
[Address[0]] => YUUSATD
)
[1] => Array
(
[id[3]] => BX-78
[Name[3]] => AAA
[Address[3]] => FSDSDS
)
[2] => Array
(
[id[4]] => BX-81
[Name[4]] => XXX
[Address[4]] => DSDSDSD
)
)
See a php demo
I've this very pragmatic approach:
$spout_output = [
[
'id[0]' => 'BX-78',
'Name[0]' => 'XXX',
'Address[0]' => 'YUUSATD'
],
[
'id[1]' => 'BX-79',
'Name[1]' => 'YYY',
'Address[1]' => 'DHJSHDJGY'
],
[
'id[2]' => 'BX-80',
'Name[2]' => 'ZZZ',
'Address[2]' => 'DDSDSDA'
],
[
'id[3]' => 'BX-78',
'Name[3]' => 'AAA',
'Address[3]' => 'FSDSDS'
],
[
'id[4]' => 'BX-81',
'Name[4]' => 'XXX',
'Address[4]' => 'DSDSDSD'
]];
// store id to row, and name to row mappings.
// id and name will be keys, value will be an array of indexes of the array $spout_output
$id_to_rows = array();
$name_to_rows = array();
$duplicate_ids = array();
$duplicate_names = array();
foreach($spout_output as $row => $data)
{
$key_id = 'id['.$row.']';
$key_name = 'Name['.$row.']';
if(!isset($data[$key_id]))
continue;
$value_id = $data[$key_id];
$value_name = $data[$key_name];
if(!isset($id_to_rows[$value_id]))
{
$id_to_rows[$value_id] = array();
}
else
{
if(!isset($duplicate_ids[$value_id]))
{
$duplicate_ids[$value_id] = $id_to_rows[$value_id];
}
$duplicate_ids[$value_id][] = $row;
}
if(!isset($name_to_rows[$value_name]))
{
$name_to_rows[$value_name] = array();
}
else
{
if(!isset($duplicate_names[$value_name]))
{
$duplicate_names[$value_name] = $name_to_rows[$value_name];
}
$duplicate_names[$value_name][] = $row;
}
$id_to_rows[$value_id][] = $row;
$name_to_rows[$value_name][] = $row;
}
echo 'Duplicates:';
echo '<br>';
$shown_rows = array();
foreach($duplicate_ids as $id => $rows)
{
foreach($rows as $nr)
{
echo $id . '|' . $spout_output[$nr]['Name['.$nr.']'] . '|' . $spout_output[$nr]['Address['.$nr.']'];
echo '<br>';
$shown_rows[] = $nr;
}
}
foreach($duplicate_names as $name => $rows)
{
foreach($rows as $nr)
{
// if already shown above, skip this row
if(in_array($nr, $shown_rows))
continue;
echo $spout_output[$nr]['id['.$nr.']'] . '|' . $spout_output[$nr]['Name['.$nr.']'] . '|' . $spout_output[$nr]['Address['.$nr.']'];
echo '<br>';
$shown_rows[] = $nr;
}
}
Outputs:
Duplicates:
BX-78|XXX|YUUSATD
BX-78|AAA|FSDSDS
BX-81|XXX|DSDSDSD
I think your 'wanted output' contains an error in the address?
Anyway, with my code above I think you'll have enough mapped data to produce the output you want.
You could do something like this:
$dupes = [];
$current = [];
foreach ($array as $index => $entry) {
$idKey = "id[$index]";
$nameKey = "Name[$index]";
if (array_key_exists($entry[$idKey], $current)) {
$dupes[] = [$entry, $current[$entry[$idKey]]];
}
elseif (array_key_exists($entry[$nameKey], $current)) {
$dupes[] = [$entry, $current[$entry[$nameKey]]];
}
else {
$current[$entry[$idKey]] = $current[$entry[$nameKey]] = $entry;
}
}
print_r($dupes);
Which results in an array containing each set of duplicates (array of arrays):
Array
(
[0] => Array
(
[0] => Array
(
[id[3]] => BX-78
[Name[3]] => AAA
[Address[3]] => FSDSDS
)
[1] => Array
(
[id[0]] => BX-78
[Name[0]] => XXX
[Address[0]] => YUUSATD
)
)
[1] => Array
(
[0] => Array
(
[id[4]] => BX-81
[Name[4]] => XXX
[Address[4]] => DSDSDSD
)
[1] => Array
(
[id[0]] => BX-78
[Name[0]] => XXX
[Address[0]] => YUUSATD
)
)
)
Demo here: https://3v4l.org/JAtNU
In case someone of you are searching unique values by key.
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array)) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}
This function just takes multidimensional array and key value of field you need.
Then takes value of given array one by one (smaller arrays).
Then traverses given array and looking if taken key-value pair matches with given key.
After that if taken key-value pair matches with given key function just inserts smaller array in temporary array (array with unique values).
Don't forget to increment indexes of arrays ($i).
Then return array you got (with unique values) after function ends work.
Here is my array:
$arr = [
1 => [
2 => "something",
3 => "something else"
],
2 => "foo br"
];
I need to restart all keys and start all of them from 0. Based on some researches, I figured out I have to use array_values() function. But it just makes the keys of outer array re-index, See.
How can I apply it on the all keys of array? (even nested ones)
You can use array_values + recursively calling custom function:
function arrayValuesRecursive($array) {
$array = array_values($array);
$countValues = count($array);
for ($i = 0; $i < $countValues; $i++ ) {
$subElement = $array[$i];
if (is_array($subElement)) {
$array[$i] = arrayValuesRecursive($subElement);
}
}
return $array;
}
$restructuredArray = arrayValuesRecursive($array);
You can implement it using recursion like this:
function reIndex($arr) {
$arr = array_values($arr);
foreach ($arr as $k => $v) {
if (is_array($v)) {
$arr[$k] = reIndex($v);
}
}
return $arr;
}
$arr = reIndex($arr);
Hi checkout following code
<?php
$arr = [
1 => [
2 => "something",
3 => "something else"
],
2 => "foo br"
];
$reIndexedArray = array();
foreach($arr as $arrItr){
$reIndexedArray[] = count($arrItr) > 1 ? array_values($arrItr) : $arrItr;
}
print_r($reIndexedArray);
?>
output is
Array
(
[0] => Array
(
[0] => something
[1] => something else
)
[1] => foo br
)
I have an array, looking like this:
[lund] => Array
(
[69] => foo
)
[berlin] => Array
(
[138] => foox2
)
[tokyo] => Array
(
[180] => foox2
[109] => Big entrance
[73] => foo
)
The thing is that there were duplicate keys, so I re-arranged them so I can search more specifically, I thought.
Previously I could just
$key = array_search('foo', $array);
to get the key but now I don't know how.
Question: I need key for value foo, from tokyo. How do I do that?
You can get all keys and value of foo by using this:
foreach ($array as $key => $value) {
$newArr[$key] = array_search('foo', $value);
}
print_r(array_filter($newArr));
Result is:
Array
(
[lund] => 69
[tokyo] => 109
)
If you don't mind about the hard code than you can use this:
array_search('foo', $array['tokyo']);
It just a simple example, you can modify it as per your requirement.
Try this
$a = array(
"land"=> array("69"=>"foo"),
"land1"=> array("138"=>"foo1"),
"land2"=> array('180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'),
);
//print_r($a);
$reply = search_in_array($a, "foo");
print_r($reply);
function search_in_array($a, $search)
{
$result = array();
foreach($a as $key1 => $array ) {
foreach($array as $k => $value) {
if($value == "$search") {
array_push($result,"{$key1}=>{$k}");
breck;
}
}
}
return $result;
}
This function will return the key or null if the search value is not found.
function search($searchKey, $searchValue, $searchArr)
{
foreach ($searchArr as $key => $value) {
if ($key == $searchKey && in_array($searchValue, $value)) {
$results = array_search($searchValue, $value);
}
}
return isset($results) ? $results : null;
}
// var_dump(search('tokyo', 'foo', $array));
Since Question: I need key for value foo, from tokyo. How do i do that?
$key = array_search('foo', $array['tokyo']);
As a function:
function getKey($keyword, $city, $array) {
return array_search($keyword, $array[$city]);
}
// PS. Might be a good idea to wrap this array in an object and make getKey an object method.
If you want to get all cities (for example to loop through them):
$cities = array_keys($array);
I created solution using array iterator. Have a look on below solution:
$array = array(
'lund' => array
(
'69' => 'foo'
),
'berlin' => array
(
'138' => 'foox2'
),
'tokyo' => array
(
'180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'
)
);
$main_key = 'tokyo'; //key of array
$search_value = 'foo'; //value which need to be search
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach ($iterator as $key => $value) {
$keys = array();
if ($value == $search_value) {
$keys[] = $key;
for ($i = $iterator->getDepth() - 1; $i >= 0; $i--) {
$keys[] = $iterator->getSubIterator($i)->key();
}
$key_paths = array_reverse($keys);
if(in_array($main_key, $key_paths) !== false) {
echo "'{$key}' have '{$value}' value which traverse path is: " . implode(' -> ', $key_paths) . '<br>';
}
}
}
you can change value of $main_key and $serch_value according to your parameter. hope this will help you.
<?php
$lund = [
'69' => 'foo'
];
$berlin = [
'138' => 'foox2'
];
$tokyo = [
'180' => 'foox2',
'109' => 'Big entrance',
'73' => 'foo'
];
$array = [
$lund,
$berlin,
$tokyo
];
echo $array[2]['180']; // outputs 'foox2' from $tokyo array
?>
If you want to get key by specific key and value then your code should be:
function search_array($array, $key, $value)
{
if(is_array($array[$key])) {
return array_search($value, $array[$key]);
}
}
echo search_array($arr, 'tokyo', 'foo');
try this:
<?php
error_reporting(E_ALL | E_STRICT);
ini_set('display_errors', 'On');
$array=array("lund" => array
(
69 => "foo"
),
"berlin" => array
(
138 => "foox2"
),
"tokyo" => array
(
180 => "foox2",
109 => "Big entrance",
73 => "foo"
));
function search($array, $arrkey1, $arrvalue2){
foreach($array as $arrkey=>$arrvalue){
if($arrkey == $arrkey1){
foreach($arrvalue as $arrkey=>$arrvalue){
if(preg_match("/$arrvalue/i",$arrvalue2))
return $arrkey;
}
}
}
}
$result=search($array, "tokyo", "foo"); //$array=array; tokyo="inside array to check"; foo="value" to check
echo $result;
You need to loop through array, since its 2 dimensional in this case. And then find corresponding value.
foreach($arr as $key1 => $key2 ) {
foreach($key2 as $k => $value) {
if($value == "foo") {
echo "{$k} => {$value}";
}
}
}
This example match key with $value, but you can do match with $k also, which in this case is $key2.
I've a multidimensional array:
array (
array (
"username" => "foo",
"favoriteGame" => "Mario"
)
array (
"username" => "bar",
"favoriteGame" => "Mario"
)
array (
"username" => "xyz",
"favoriteGame" => "Zelda"
)
)
How could I get the usernames of the persons that like to play for example Mario the easiest way possible?
EDIT:
My fault: forget to explicitly mention that the "favoriteGame" value is dynamic and I cannot know which it is in advance.
My Solution:
foreach($users as $key => $value)
{
if(!isset($$value['favoriteGame']))
{
$$value['favoriteGame'] = array();
}
array_push($$value['favoriteGame'], $value['username']);
}
Iterate over each sub-array and find its favoriteGame value.
If there is not already an array $favoriteGame create it.
Push the username-value of the actual sub-array to the $favoriteGame array.
Thanks for your replies, I just couldn't phrase this question properly.
function getUsernamesByFavoriteGame($data, $game) {
$usernames = array();
foreach($data as $arr) {
if ($arr['favoriteGame'] == $game) {
$usernames[] = $arr['username'];
}
}
return $usernames;
}
$usernames = array();
foreach($array as $key => $value) {
if ($value['favoriteGame'] == 'Mario') {
$usernames[] = $value['username'];
}
}
I would use array_filter. If you have PHP 5.3 or up, you can do it like this:
$favorite = "Mario";
$filter = function($player) use($favorite) { return $player['favoriteGame'] == $favorite; };
$filtered = array_filter($players, $filter);
It will be a little different for older versions because you won't be able to use lambda functions.
$game = 'Mario';
$users = array();
foreach($array as $key => $value) {
if ($value['favoriteGame'] == $game) {
$users[] = $value['username'];
}
}
If you are using this more often then convert the data structure to something like this.
array(
"Mario" => array(
"0":"foo",
"1":"xyz"
)
"Zelda" => array(
"0":"pqr",
"1":"abc"
)
)
This will directly give you list of user names for a favorite game.
$arr[$favGame]
If you cannot change the data structure then go with with tigrang has suggested.
I think you should implement a custom multidimensional search function.
Take a look at this answer.
Here's how you would use it
Code | Live example
function search($array, $key, $value){
$results = array();
if (is_array($array))
{
if (isset($array[$key]) && $array[$key] == $value)
$results[] = $array;
foreach ($array as $subarray)
$results = array_merge($results, search($subarray, $key, $value));
}
return $results;
}
$arr = array (
array (
"username" => "foo",
"favoriteGame" => "Mario"
),
array (
"username" => "bar",
"favoriteGame" => "Mario"
),
array (
"username" => "xyz",
"favoriteGame" => "Zelda"
)
);
print_r(search($arr, 'favoriteGame', 'Mario'));
//OUTPUT
Array (
[0] => Array (
[username] => foo
[favoriteGame] => Mario
)
[1] => Array (
[username] => bar
[favoriteGame] => Mario
)
)
$array = array( 'a' => 'A',
'b'=>'B',
'c'=>'C',
'd'=>array(
'e'=>array(
'f'=>'D'
),
'g'=>array(
'h'=>'E'
)
),
'i'=>'F',
'j'=>array(
'k'=>'G'
),
'l'=>'H'
);
$new_array = array();
foreach($array as $k1=>$v1){
if(is_array($v1)){
$new_array = parseArray($new_array, $k1, $v1);
}else{
$new_array = array_merge($new_array, array($k1=>$v1));
}
}
function parseArray($new_array, $key, $val){
if(is_array($val)){
foreach($val as $k2=>$v2){
if(is_array($v2)){
$new_array = parseArray($new_array, $k2, $v2);
}else{
$new_array = array_merge($new_array, array($k2=>$v2));
}
}
}else{
$new_array = array_merge($new_array, array($key=>$val));
}
return $new_array;
}
Output
Array
(
[a] => A
[b] => B
[c] => C
[f] => D
[h] => E
[i] => F
[k] => G
[l] => H
)