convert array with objects to one associative array without foreach - php

I have an array like(result of json_decode):
array(2) {
[0]=>
object(stdClass)#1 (3) {
["key"]=>
string(6) "sample"
["startYear"]=>
string(4) "2000"
["endYear"]=>
string(4) "2015"
}
[1]=>
object(stdClass)#2 (3) {
["key"]=>
string(13) "second_sample"
["startYear"]=>
string(4) "1986"
["endYear"]=>
string(4) "1991"
}
}
I want to convert it to array like:
array(2) {
["sample"]=>
array(2) {
["startYear"]=>
string(4) "2000"
["endYear"]=>
string(4) "2015"
}
["second_sample"]=>
array(2) {
["startYear"]=>
string(4) "1986"
["endYear"]=>
string(4) "1991"
}
}
Is there beauty way to do this (cureently I'm using foreach, but I'm not sure it is a best solution).
Added a code example:
<?php
$str='[{"key":"sample","startYear":"2000","endYear":"2015"},{"key":"second_sample","startYear":"1986","endYear":"1991"}]';
$arr=json_decode($str);
var_dump($arr);
$newArr=array();
foreach ($arr as $value){
$value=(array)$value;
$newArr[array_shift($value)]=$value;
}
var_dump($newArr);

You can use array_reduce
$myArray = array_reduce($initialArray, function ($result, $item) {
$item = (array) $item;
$key = $item['key'];
unset($item['key']);
$result[$key] = $item;
return $result;
}, array());

You can create the desired output without making any iterated function calls by using a technique called "array destructuring" (which is a functionless version of list()). Demo
Language Construct Style:
$result = [];
foreach ($array as $object) {
[
'key' => $key,
'startYear' => $result[$key]['startYear'],
'endYear' => $result[$key]['endYear']
] = (array)$object;
}
var_export($result);
Functional Style:
var_export(
array_reduce(
$array,
function($result, $object) {
[
'key' => $key,
'startYear' => $result[$key]['startYear'],
'endYear' => $result[$key]['endYear']
] = (array)$object;
return $result;
},
[]
)
);
Both will output:
array (
'sample' =>
array (
'startYear' => '2000',
'endYear' => '2015',
),
'second_sample' =>
array (
'startYear' => '1985',
'endYear' => '1991',
),
)

Simply you can use array_map like as
$result = array_map('get_object_vars',$your_array);
Edited:
As after checking your code that you've added an example over here there's no need to use an extra functions or loop to convert your array of objects into associative array instead you simply need to pass second parameter true within json_decode function like as
$arr = json_decode($json,true);
Demo

An alternative to array_reduce and other provided solutions could be:
$list = array_combine(
array_column($list, 'key'),
array_map(fn ($item) => (array) $item, array_values($list))
);
Or:
$list = array_combine(
array_column($list, 'key'),
array_map('get_object_vars', $list)
);

Related

How to sort a multidimensional class in php with different subarray name

Can someone help me about my problem... I have a php multidimensional array and i need to sort it by "PRICE" with PHP... I tried to use sort() but it don't work because every main array have a different currency name..
Here is an example of my array :
array(3) {
["MLN"]=>
array(1) {
["EUR"]=>
array(23) {
["FROMSYMBOL"]=>
string(3) "MLN"
["TOSYMBOL"]=>
string(3) "EUR"
["PRICE"]=>
float(0.01699)
}
}
["BTC"]=>
array(1) {
["EUR"]=>
array(23) {
["FROMSYMBOL"]=>
string(3) "BTC"
["TOSYMBOL"]=>
string(3) "EUR"
["PRICE"]=>
int(8769)
}
}
["LTC"]=>
array(1) {
["EUR"]=>
array(23) {
["FROMSYMBOL"]=>
string(3) "LTC"
["TOSYMBOL"]=>
string(3) "EUR"
["PRICE"]=>
float(141.47)
}
}
}
Is someone who have an idea to sort my currencies by PRICE?
Thanks a lot
You could use uasort():
uasort($array, function($a, $b) {
return $a['EUR']['PRICE'] - $b['EUR']['PRICE'];
});
I'm using an anonymous function in this example but you could also define the comparison function separately.
You could try something like this :
$sorted = [] ;
foreach ($array as $key => $item) {
$price = reset($item)['PRICE'] ;
$sorted[$price] = [$key => $item] ;
}
krsort($sorted);
$array = [];
foreach ($sorted as $sort) {
$keys = array_keys($sort) ;
$array[reset($keys)] = reset($sort) ;
}
unset($sorted);
print_r($array);
Will keep keys and sort array.
Output :
Array
(
[BTC] => Array
(
[EUR] => Array
(
[FROMSYMBOL] => BTC
[TOSYMBOL] => EUR
[PRICE] => 8769
)
)
[LTC] => Array
(
[EUR] => Array
(
[FROMSYMBOL] => LTC
[TOSYMBOL] => EUR
[PRICE] => 141.47
)
)
[MLN] => Array
(
[EUR] => Array
(
[FROMSYMBOL] => MLN
[TOSYMBOL] => EUR
[PRICE] => 0.01699
)
)
)
If you want a somewhat messy object oriented approach, I've made a class that is supposed to order an array of classes based on a shared property:
https://gist.github.com/kyrrr/b208693a59f184fe607660e0dfa8631d
A class that represents your data (quick and dirty):
class Exchange{
public $currencyName;
public $toSymbol;
public $rate;
function __construct($name, $to, $rate)
{
$this->currencyName = $name;
$this->toSymbol = $to;
$this->rate = $rate;
}
}
Then you can do:
$orderer = new PropertyOrderHelper();
$foo = new Exchange("MLN", "EUR", 0.0169);
$bar = new Exchange("BTC", "EUR", 20);
$exchanges = [$foo, $bar];
var_dump($orderer->orderBy($exchanges, "rate"));
var_dump($orderer->orderBy($exchanges, "rate", 'desc'));

How to merge subarrays using keys and sum the values?

I'm fairly new to PHP and I'm having some trouble with arrays and combining data. I have the following array which has been created from a foreach loop:
array(1) {
[36868]=> int(3)
}
array(1) {
[2112]=> int(3)
}
array(1) {
[35901]=> int(3)
}
array(1) {
[6496]=> int(3)
}
array(1) {
[87]=> int(3)
}
array(1) {
[36868]=> int(3)
}
array(1) {
[68]=> int(3)
}
array(1) {
[9068]=> int(3)
}
array(1) {
[47]=> int(3)
}
The key in each array is a user ID, so I need to preserve this, but I only want one instance of each key and where there are duplicate keys, sum the values. Like so:
array(1) {
[36868]=> int(6)
}
array(1) {
[2112]=> int(3)
}
array(1) {
[35901]=> int(3)
}
array(1) {
[6496]=> int(3)
}
array(1) {
[87]=> int(3)
}
array(1) {
[68]=> int(3)
}
array(1) {
[9068]=> int(3)
}
array(1) {
[47]=> int(3)
}
The I've tried looping through the array:
foreach ($array as $key => &$value) {
if ($value[0] == $value[1]) {
$value[1] += $value[1];
}
}
But with no luck. I've also tried rendering the arrays differently i.e. [userid]=>1,[score]=>3 and I feel like I'm going round in circles a bit, so any help would be hugely appreciated.
$data <-- this is your original array
$result = array_reduce(
$data,
function($carry, $item) {
foreach ($item as $id => $score) {
if (array_key_exists($id, $carry)) {
$carry[$id] += $score;
} else {
$carry[$id] = $score;
}
}
return $carry;
},
[]
);
If you are sure that each item only contains 1 entry you could also simplify the callback to not use foreach:
$result = array_reduce(
$data,
function ($carry, $item) {
$score = reset($item);
$id = key($item);
if (array_key_exists($id, $carry)) {
$carry[$id] += $score;
} else {
$carry[$id] = $score;
}
return $carry;
},
[]
);
You could also keep using foreach instead:
/** foreach to create a $data array like described below and afterwards do this: **/
$result = [];
foreach($data as $row) {
$score = reset($row);
$id = key($row);
if (array_key_exists($id, $result)) {
$result[$id] += $score;
} else {
$result[$id] = $score;
}
}
This will take an array $data like this:
array(
array('1' => 3),
array('1' => 3),
array('2' => 3),
);
and creates the variable $result like this:
array(
'1' => 6,
'2' => 3,
);
Here is a clean method that will not produce Notices. When merge-summing array data the efficient method is to generate temporary keys and use the very fast isset() function. I could have used current() and key() to access the lone subarray element, but the second foreach control structure is actually faster and more compact. (Ref:
https://stackoverflow.com/a/21219594/2943403 )
Code: (Demo)
$array = [
[36868 => 3],
[2112 => 3],
[35901 => 3],
[6496 => 3],
[87 => 3],
[36868 => 3],
[68 => 3],
[9068 => 3],
[47 => 3]
];
$result = [];
foreach ($array as $subarray) {
foreach ($subarray as $k => $v) {
if (!isset($result[$k])) {
$result[$k] = $subarray;
} else {
$result[$k][$k] += $v;
}
}
}
var_export(array_values($result));
Output:
array (
0 =>
array (
36868 => 6,
),
1 =>
array (
2112 => 3,
),
2 =>
array (
35901 => 3,
),
3 =>
array (
6496 => 3,
),
4 =>
array (
87 => 3,
),
5 =>
array (
68 => 3,
),
6 =>
array (
9068 => 3,
),
7 =>
array (
47 => 3,
),
)

Change indexed Array to Associative Array PHP

I have an array from json_decode. And i want to reformat it.
this is my array format.
["Schedule"]=>array(1) {
["Origin"]=>
string(3) "LAX"
["Destination"]=>
string(2) "CGK"
["DateMarket"]=>
array(2) {
["DepartDate"]=>
string(19) "2015-02-01T00:00:00"
["Journeys"]=>
array(6) {
[0]=>
array(6) {
[0]=>
string(2) "3210"
[1]=>
string(14) "Plane Name"
[2]=>
string(8) "20150201"
[3]=>
string(8) "20150201"
[4]=>
string(4) "0815"
[5]=>
string(4) "1524"
}
}
}
And i want change the indexed array to associative with foreach function.
And here is my PHP code
foreach ($response->Schedule['DateMarket']['Journeys'] as $key=>$value) {
$value->Name= $value[1];
}
But i got an error "Attempt to assign property of non-object on line xXx..
My Question is, how to insert a new associative array to indexed array like the example that i've provide.
UPDATE : I've tried this solution
foreach ($response->Schedule['DateMarket']['Journeys'] as $key=>$value) {
$value['Name']=$value[1];
}
But my array format still the same, no error.
In this line:
$value->Name= $value[1];
You expect $value to be both object ($value->Name) and array ($value[1]).
Change it to something like:
foreach ($response->Schedule['DateMarket']['Journeys'] as $key=>$value) {
$response->Schedule['DateMarket']['Journeys'][$key]['Name'] = $value[1];
}
Or even better, without foreach:
$keys = array(
0 => 'Id',
1 => 'Name',
2 => 'DateStart',
3 => 'DateEnd',
4 => 'HourStart',
5 => 'HourEnd',
);
$values = $response->Schedule['DateMarket']['Journeys'];
$response->Schedule['DateMarket']['Journeys'] = array_combine( $keys , $values );
Array_combine makes an array using keys from one input and alues from the other.
Docs: http://php.net/manual/en/function.array-combine.php
Try this:
foreach ($response->Schedule['DateMarket']['Journeys'] as $key=>$value) {
$value['Name'] = $value[1];
}
You want to create new array index, but try to create new object.
foreach ($response->Schedule['DateMarket']['Journeys'] as $key => $value) {
$value['Name'] = $value[1];
}

Delete part of index name in multidimensional array

in PHP, is it possible to cut the |xyz part away from the key names?
The array looks like this:
array(30) {
["1970-01-01|802"]=>
array(4) {
["id"]=>
string(3) "176"
["datum"]=>
string(10) "1970-01-01"
["title"]=>
string(8) "Vorschau"
["alias"]=>
string(16) "vorschau-v15-176"
}
["1970-01-01|842"]=>
array(4) {
["id"]=>
string(3) "176"
["datum"]=>
string(10) "1970-01-01"
["title"]=>
string(8) "Vorschau"
["alias"]=>
string(16) "vorschau-v15-176"
} ...
Thank you for your help,
toni
For example, you might use this:
$newArray = array();
foreach( $oldArray as $key => $value ) {
$newArray[ substr( $key, 0, 10 ) ] = $value;
}
Or modify the array in-place:
foreach( $someArray as $key => $value ) {
unset( $someArray[ $key ] );
$someArray[ substr( $key, 0, 10 ) ] = $value;
}
Both solutions will loose value
Since the keys in your source array are
1970-01-01|802
1970-01-01|842
the output array will loose some array values: Both keys get mapped to a single destination key:
1970-01-01
Keeping all values
If you don't want to loose values, try this:
$newArray = array();
foreach( $someArray as $key => $value ) {
$newKey = substr( $key, 0, 10 );
if ( ! isset( $newArray[ $newKey ] )) {
$newArray[ $newKey ] = array();
}
$newArray[ $newKey ][] = $value;
}
Result array structure of this solution:
array(
'1970-01-01' =>
array(
0 => ...,
1 => ...
),
'1970-01-02' =>
array(
0 => ...,
1 => ...,
2 => ...
),
...
);
Kind of.. just create a new array with the trimmed key, then set the old aray equal to the new one.
$newArray = array();
foreach ($arrayList as $key => $data) {
$keyParts = explode("|", $key);
$newArray[$keyParts[0]] = $data;
}
$arrayList = $newArray;
It could be possible but in this case you would end up with 2 of the same array keys.
["1970-01-01"] and ["1970-01-01"]
The xyz behind it is required in this case.
You can do it with preg_replace:
$keys = preg_replace('/(.+)\|\d+/', '$1', array_keys($arr));
$arr = array_combine($keys, $arr);

Filter out keys from multidimensional array

I have the following array:
array(2) {
[0] => array(4) {
["presentation_id"] => int(143)
["user_id"] => int(2)
["session_id"] => int(46)
["submission_id"] => int(190)
}
[1] => array(4) {
["presentation_id"] => int(144)
["user_id"] => int(2)
["session_id"] => int(46)
["submission_id"] => int(190)
}
What I want is to have an array consisting of just certain keys of this array, for example:
array(2) {
[0] => array(4) {
["presentation_id"] => int(143)
["user_id"] => int(2)
}
[1] => array(4) {
["presentation_id"] => int(144)
["user_id"] => int(2)
}
Any ideas?
$array = array_map(function ($arr) {
return array_intersect_key($arr, array_flip(array('presentation_id', 'user_id')));
}, $array);
Important to note that this syntax requires PHP 5.3+.
For other versions:
foreach ($array as &$arr) {
$arr = array_intersect_key($arr, array_flip(array('presentation_id', 'user_id')));
}
I'd suggest this over unsetting unwanted keys (as suggested by others) if you definitely want to restrict the array to certain elements. If you add more elements to the array in the future you won't need to update this code, but you'd have to unset more elements that you may not want.
Try:
$newArray = array_map(function ($innerArray) {
unset($innerArray['session_id'], $innerArray['submission_id'] /*, and so on*/);
return $innerArray;
}, $oldArray);
please use foreach and unset the key which you want to remove. Like
foreach($data as $key=> $row){
unset[$key] ["session_id"] ;
}

Categories