I have a PHP function that give me two seperate JSON arrays (array1 and array2). How can I merge them in an object with properties, like this:
{
"array1": [ {"type": "column", "valueField": ..., "descriptionField": ..., }]
"array2": [ {"type": "column", "valueField": ..., "descriptionField": ..., }]
}
Thanks in advance
This is just a simple example of how you can do it, you can improve it however you like, depending what kind of situation you need it for.
// Initialising arrays
$array1 = ['type' => 'column', 'valueField' => '.1.', 'descriptionField' => '.11.'];
$array2 = ['type' => 'column', 'valueField' => '.2.', 'descriptionField' => '.22.'];
// Turn them manually into jsons
$obj1 = json_encode($array1);
$obj2 = json_encode($array2);
// Merge the two jsonified arrays in a single array with whichever keys you prefer
$mix = ['array1' => $obj1, 'array2' => $obj2];
// Turn the merged "mix" array into json
$mix = json_encode($mix);
// Check the output
printf($mix);
/* Prints out:
{
"array1":"{"type":"column", "valueField":".1.", "descriptionField":".11."}",
"array2":"{"type":"column", "valueField":".2.", "descriptionField":".22."}"
}
*/
You can fiddle around with it in in this SANDBOX, have some fun with it.
Related
I have an array of objects, and want to update an attribute of one of the objects.
$objs = [
['value' => 2, 'key' => 'a'],
['value' => 3, 'key' => 'b'] ,
];
Let's say I want to set the 'value' of the object with 'key'=>'a' to 5.
Aside from iterating over the array searching for the key, is there any quicker/efficient way of doing this?
Thanks.
EDIT: There is debate as to why I can't use an associative array. It is because this array is obtained from a JSON value.
If my JSON object is this:
"obj": {
"a": {
"key": "a",
"value": 2
},
"b": {
"key": "b",
"value": 3
}
}
There is no guarantee that the order of the objects will be retained, which is required.
Hence I need an index in each object to be able to sort it using usort(). So my JSON needs to be:
"obj": {
"a": {
"key": "a",
"value": 2,
"index": 1
},
"b": {
"key": "b",
"value": 3,
"index": 2
}
}
But I cannot use usort() on an object, only on arrays. So my JSON needs to be
"obj": [
{
"key": "a",
"value": 2,
"index": 1
}, {
"key": "b",
"value": 3,
"index":2
}
]
Which brings us to the original question.
By using array_column(), you can pull all the values with the index key in the arrays. Then you can find the first occurrence of the value a by using array_search(). This will only return the first index where it finds a value. Then you can simply replace that value, as you now have the index of that value.
$keys = array_column($objs, 'key');
$index = array_search('a', $keys);
if ($index !== false) {
$objs[$index]['value'] = 5;
}
See this live demo.
http://php.net/array_search
http://php.net/array_column
You can make the array associative with array column. That way you can directly assign the value.
$objs = [ ['value'=>2, 'key'=>'a'], ['value'=>3, 'key'=>'b'] ];
$objs = array_column($objs, null, "key");
$objs['a']['value'] = 5;
https://3v4l.org/7tJl0
I want to recommend you reorginize your array lake that:
$objs = [
'a' => ['value'=>2, 'key'=>'a'],
'b' => ['value'=>3, 'key'=>'b']
];
And now
if( array_key_exists( 'a', $objs )) {
$objs ['a'] ['value'] = 5;
}
I had it like that initially. But I need for the objects to have an
index value in them, so I can run usort() on the main array. This is
because the array comes from JSON where the original order isn't
respected
Then create an index array:
// When fill `$objs` array
$objs = [];
$arrIndex = [];
$idx = 0;
foreach( $json as $item ) {
$arrIndex [ $item ['key']] = $idx;
$objs [$idx ++] = $item;
}
// And your task:
if( array_key_exists( 'a', $arrIndex )) {
$objs [ $arrIndex ['a']] ['value'] = 5;
}
Aside from iterating over the array searching for the key, is there
any quicker/efficient way of doing this?
You have to pay the price of iteration either way.
You can search your collection for the interesting object (takes linear time), or you form some kind of dictionary data structure, e.g. hash table (takes linear time) and then find the interesting object in constant time.
No free lunches here.
I want to repeat the unit and pcs sections in the JSON file.
For example:
$rows[] = array(
'unit' => 'Example',
'pcs' =>
array('1 for Example', '2 for Example'),
);
Result:
[
{"unit":"Example","pcs":["1 for Example","2 for Example"]}
]
How to do this type of JSON?
Target:
[
{"unit":"Example",
"pcs":
["1 for Example","2 for Example"]},
{"unit":"ExampleSecond",
"pcs":
["1 for ExampleSecond","2 for ExampleSecond"]}
]
Simple: Just create a (nested) PHP array and call json_encode on it. Numeric arrays translate into JSON lists ([]), associative arrays and PHP objects translate into objects ({}). Example:
$a = array(
array('foo' => 'bar'),
array('foo' => 'baz'));
$json = json_encode($a);
Gives you:
[{"foo":"bar"},{"foo":"baz"}]
I've got simple array of objects:
"myObject" => [
'key1' => ["property1" => 'value1', "property2" => 'value2'],
'key2' => ["property1" => 'value1', "property2" => 'value2'],
...
],
When I'm returning this via laravel dot syntax:
return [
'listOfObjects' => trans(objects)
]
I've got:
myObject: {
key1: {property1:'value1', property2:'value2'},
key2: {property1:'value1', property2:'value2'},
etc..
}
It's simple.
Now how can I modify my return to get only an array of objects, without numbers:
myObject: {
{property1:'value1', property2:'value2'},
{property1:'value1', property2:'value2'},
etc..
}
Any ideas?
I don't think it is possible to solve in PHP. As it is said in the manual
"...index may be of type string or integer. When index is omitted, an
integer index is automatically generated, starting at 0..."
Also, what you are asking seems to be quite pointless. If you could describe what it is you are trying to accomplish, people might be able to help you better.
The function to use in this case is:
$tryit = trans('objects');
$new = collect($tryit)->flatten(1);
$new->values()->all();
unfortunatelly there is a bug in Laravel 5.6 on this function and it digs two level deep instead of one :/
[edit]
I think I now understand what you want. What you call an Array in PHP is not necessarily an Array in JSON. For JSON your "myObject" is an Object.
For JSON to recognize something as an Array, it can only have numbers as keys.
So change the keys from "key1", "key2", ... into 0, 1, ...
$result = [];
foreach($myObject as $element){
$result[] = $element;
}
return $result;
After that, $result looks like this
$result = [
0 => ["prop1" => "val1", "prop2" => "val2"],
1 => ["prop1" => "val1", "prop2" => "val2"]
]
Or equivalently in the short notation
$result = [
["prop1" => "val1", "prop2" => "val2"],
["prop1" => "val1", "prop2" => "val2"]
]
Now JSON should recognize this as an Array instead of an Object when Laravel converts $result to JSON or you make it yourself: return response()->json($result);
[previous:]
You can not return an object which has values but no keys.
The simplest form of keys are numbers, which is what arrays are using.
I need to push a new property into my array of arrays of objects using the values from a flat array.
My sample arrays:
$users = [
[
(object) ["user_id" => 2]
],
[
(object) ["user_id" => 1],
(object) ["user_id" => 1],
],
[
(object) ["user_id" => 2],
(object) ["user_id" => 2]
]
];
$is_admin = [
false,
true,
true,
false,
false
];
I need to write is_admin => [boolean value] (one at a time) into each object using the values from the second array.
Desired result:
[
[
(object) ["user_id" => 2, "is_admin" => false]
],
[
(object) ["user_id" => 1, "is_admin" => true],
(object) ["user_id" => 1, "is_admin" => true],
],
[
(object) ["user_id" => 2, "is_admin" => false],
(object) ["user_id" => 2, "is_admin" => false]
]
]
I do not know how to map the second array with the first array's structure. I have tried using array_merge, but it doesn't work properly with my data structure and requirements.
You can use array_walk_recursive function:
array_walk_recursive($users, function (&$user) use (&$is_admin) {
$user->is_admin = current($is_admin);
next($is_admin);
});
Pay attention that both $user and $is_admin passed by reference.
Also, you can use outer index variable (i.e. $i) to track $is_admin position. In such case, you need to pass (to be more precise enclose) $i along side with $is_admin, only $i will be passed by reference and $is_admin by value. I decided to take advantage of current and next functions, not introducing one more variable.
Here is working demo.
One important thing. If your $is_admin array has fewer elements than $users arrays (they are leaves actually) false value will be assigned to the is_admin field of those users that comes after the point when there are no elements left in $is_admin.
I don't think you can achieve that because the arrays are very different. Since they're of different size the array_merge won't work properly. Plus, the first array is multidimensional while the 2nd array is single-dimensional.
If you are 100% certain about the mapping between the indexes of array a and b you can create a loop as follows, assuming that $array1 is the multidimensional array and $array2 is the flat array containing true and false:
$index = 0;
$final = array_map(function ($top_level_entry) {
return array_map(function ($item) {
global $index, $array2;
$item['is_admin'] = $array2[$index];
$index++;
return $item;
}, $top_level_entry);
}, $array1);
or in a simpler format:
$index = 0;
$final = [];
foreach ($array1 as $i => $arr) {
foreach($arr as $j => $user) {
$user['is_admin'] = $array2[$index];
$index++;
$arr[$j] = $user;
}
$final[$i] = $arr;
}
As an exercise in enjoying reference variables, I'll demonstrate assigning deep reference variables within a nested loop then looping over the $is_admin array to apply the values to those variables.
Admittedly, this does more loops than the other answers, but it should be said that it doesn't make any iterated function calls, does not need to maintain an incremented counter, and will not suffer if there are fewer values than reference variables (not that that is a problem with the asker's question).
Code: (Demo)
foreach ($users as &$groups) {
foreach ($groups as $obj) {
$obj->is_admin = &$refs[];
}
}
foreach ($is_admin as $i => $bool) {
$refs[$i] = $bool;
}
var_export($users);
Because objects in PHP have a default behavior of being modifiable by reference, you will notice that $obj in the nested loop is not prefixed with & -- it could have been for consistency, but it was not necessary.
As mentioned above the snippet, if there aren't enough elements in $is_admin to cover all of the reference variables declared in $users, then they will have a default value of null.
First this is not a duplicate questions. I've looked through some similar problem and most of the answer is what I am using right now.
Here is the problem set up,
on PHP side
$array = array('name' => 'a', 'data' => array('0'=>15,'0.25'=>'18','0.35'=>19,'1' =>20));
echo json_encode($array);
on the JS side
data = $.parseJSON(data); // data is the return from the php script
above
As you can see the $array['data'] is an associative array with numeric number as its key and sorted in order. While parsing into JSON, javascript altered the order of that array and sorted 0 and 1 as numeric key and put them to the head of the object.
I know this is standard behavior for certain browser such as chrome, and IE9.
I've read somewhere that people suggest stick with array strictly if I want to maintain the order of the array.
But my question is how do you feed back an array from PHP to javascript as an array instead of using json object? Or is there other solution to this kind of problem . Thanks for the input in advance.
Thanks for the input in advance
Use an array to maintain order, and then an object to create the map. There are two ways. I would suggest:
$array = array('name' => 'a', 'data' =>
array(
array('key' => 0, 'value' => 15),
array('key' => 0.25, 'value' => 18),
array('key' => 0.35, 'value' => 19),
array('key' => 1, 'value' => 20),
)
);
echo json_encode($array);
Which will give you the JSON:
{
"name": "a",
"data": [
{"key": 0, "value": 15},
{"key": 0.25, "value": 18},
{"key": 0.35, "value": 19},
{"key": 1, "value": 20}
]
}
Then you will have order but to look up a certain key will be more difficult. If you want that to be easy you can return a mapping object as well like this:
$array = array('name' => 'a', 'data' =>
array(
"0" => 15,
"0.25" => 18,
"0.35" => 19,
"1" => 20,
),
'order' => array("0", "0.25", "0.35", "1")
);
echo json_encode($array);
Which will give you:
{
"name": "a",
"data": {
"0": 15,
"0.25": 18,
"0.35": 19,
"1": 20
},
"order": ["0", "0.25", "0.35", "1"]
}
One of these two methods of returning your data should prove to be the most useful for your specific use case.
Actually, it's PHP that takes the "0" and "1" keys and makes them numeric keys. This has nothing to do with your JavaScript.
There isn't any real way to work around this, but ideally your code should not rely on such things as "what order the keys of an object are in". It may be a better idea, just from what I see here, to separate the data into an array of keys and an array of values, then zip them back together on the JS side.
I'd suggest another field for storing order.
$array = array('name' => 'a',
'data' => array('0'=>15,'0.25'=>'18','0.35'=>19,'1' =>20),
'order'=> '0,0.25,0.35,1'
);
echo json_encode($array);