i'm working on a project where i have a structured object like this:
$main_array= [
[
"key"=> "home",
"value":=> "Go Home!"
],
[
"key"=> "business",
"value"=> "Go to Work!"
],
[
"key"=> "other",
"value"=> "Go where you want!"
]
]
i'd like to know if there is a way to retrieve the object based on the "key" parameter.
What i want to do is "extract" the nested array like
$home_array=["key"=> "home","value":=> "Go Home!"]
and so on for "business" and "others".
in javascript, i can use jquery or underscore to get what i want, is there a php method to achieve this, or something to simulate a "where" clause in a multidimensional array/object?
thak you in advance
You can easily convert the array you have to have the 'key' column to be the main index using array_column()...
$main_array= [
[
"key"=> "home",
"value"=> "Go Home!"
],
[
"key"=> "business",
"value"=> "Go to Work!"
],
[
"key"=> "other",
"value"=> "Go where you want!"
]
];
$out = array_column($main_array, null, "key");
print_r($out['business']);
Outputs...
Array
(
[key] => business
[value] => Go to Work!
)
A few possibilities to get a single item matching a specific key:
Iterate the main array and stop when you get to a child that has the proper key:
$object = (function($key) use($main_array) {
foreach ($main_array as $object) {
if ($object['key'] == $key) return $object;
}
})('business');
(This example uses an anonymous function, but you can just use a simple foreach loop and break when you find the key.)
Reindex the main array and look up the child by key:
$indexed = array_column($main_array, null, 'key');
$object = $indexed['business'];
Construct the array using the key as the index to begin with. Using string keys doesn't preclude the array elements being other arrays that can contain multiple values.
$main_array= [
'home' => ["value"=> "Go Home!"],
'business' => ["value"=> "Go to Work!"],
'other' => ["value"=> "Go where you want!"]
];
Methods 2 and 3 require that they key is unique. Method 1 doesn't, but it will just return the first instance it finds.
If you do have multiple instances of a key, you probably want array_filter. This will work more like the "where clause" you referred to.
$key = 'home';
$filtered = array_filter($main_array, function($item) use ($key) {
return $item['key'] == $key;
});
This will return multiple items instead of just one.
Related
Not sure if my question is clear, but here's what I'm trying to achieve. Let’s say I have a multidimensional array like so:
$arr['client1']**['dog']['Jack']**
$arr['client2']['cat']['Stacy']
How can I get the second portion of the array (between **), knowing it can be anything. For client 3, it could be a crocodile. For Client 4, it could be a car.
So I'm looking to "build" the structure of the array, dynamically. Something like so:
$arr['client1']{partBetweenThe**InTheExemple}
{partBetweenThe**InTheExemple} would be constructed "on the fly" (hence, the dynamically).
EDIT: Hopefully some clarifications...
The array changes every time. Basically, I'm building an addon to poll any API on the web. The data structure I'm getting can be anything. So what I need to do is build the key combination "on the fly", with variables.
In the exemple above, my variable would be something like $query = ['dog']['Jack'] and to get the value, I would poll it like so (from a logistic perspective, I know this doesn't work):
$arr['client1'][$query] or $arr['client1']$query or $arr['client1']{$query}
You can define the query as an array with each level as an element. Then we can iterate through that and check if we find a matching key in the response:
function findInArray(array $query, array $data)
{
foreach ($query as $key) {
if (!array_key_exists($key, $data)) {
// The key was not found, abort and return null
return null;
}
// Since the key was found, move to next level
$data =& $data[$key];
}
return $data;
}
// Example response
$response = [
'client1' => [
'dog' => [
'Jack' => 'Some value',
],
]
];
// Define the query as an array
$query = ['dog', 'Jack'];
$result = findInArray($query, $response['client1']);
Demo: https://3v4l.org/WjXTn
Edit:
So since the array's structure can't be changed this will return the client if the structure remains ['client']['animal']['name'].
$clients = [
'client1' => [
'dog' => [
'Jack' => []
]
],
'client2' => [
'cat' => [
'Stacy' => []
]
]
];
$animal = 'dog';
$name = 'Jack';
foreach ($clients as $client => $options) {
if (
array_key_exists($animal, $options) &&
array_key_exists($name, $options[$animal])
) {
echo $client;
break;
}
}
I have a multidimensional array that looks like this:
"fields" => {
"name": "John"
"lastname": "Doe"
}
"data" => {
"person": array:2 [
0 => {
"adress": "foo"
"phone": "bar"
},
1 => {
"adress": "foo1"
"phone": "bar1"
}
]
}
Now I want to check that in this multidimensional array the follow keys exist so my second array to compare looks like this:
[
'fields' => [
"name",
"lastname",
],
"data" => [
"person" => [
"adress",
"phone"
]
],
]
Now here's what I've tried to compare the keys of my second array with the first array:
$result = array_diff_key($firstArray, array_flip($secondArray));
But this gives me an
array_flip(): Can only flip STRING and INTEGER values!
So I need a way to recursively flip the array or maybe I am doing it a bit wrong
I have a multidimensional array that looks like this ...
This is not an array, whatever you've done it now is amorphous trash, not an array not an json object.
$result = array_diff_key($firstArray, array_flip($secondArray));
array_diff_key() finds differences - unique keys
array_flip() replaces keys with values in the array
So I need a way to recursively flip the array or maybe I am doing it a bit wrong
Don't flip arrays, stop searching differences if you want to find the same keys.
You need at least 2 arrays (or objects) to comparison. If you will have 2 (not nested) arrays use
array_intersect_key($array1,$array2);
For nested arrays... you have to get all the keys and then compare.
I have a big chunk of data in this format:
[
{"date":"2018-11-17"},{"weather":"sunny"},{"Temp":"9"},
{"date":"2014-12-19"},{"Temp":"10"},{"weather":"rainy"},
{"date":"2018-04-10"},{"weather":"cloudy"},{"Temp":"15"},
{"date":"2017-01-28"},{"weather":"sunny"},{"Temp":"12"}
]
Is there any faster and more efficient way to organize and save it the database for future reference? Like making a comparison of the temperature for different days etc. [date,weather,Temp] are supposed to be in one set.
I've tried str_replace() but I'd like to know if there's any better way.
Taking into account your comment, it seems that is an array of objects in which every three objects make a record (that is form of: date, weather & temp) so you can create this setup with the help of collections:
$string = ['your', 'json', 'string'];
$records = collect(json_decode($string))
->chunk(3) // this creates a subset of every three items
->mapSpread(function ($date, $weather, $temp) { // this will map them
return array_merge((array) $date, (array) $weather, (array) $temp);
});
This will give you this output:
dd($records);
=> Illuminate\Support\Collection {#3465
all: [
[
"date" => "2018-11-17",
"weather" => "sunny",
"Temp" => "9",
],
[
"date" => "2014-12-19",
"Temp" => "10",
"weather" => "rainy",
],
[
"date" => "2018-04-10",
"weather" => "cloudy",
"Temp" => "15",
],
[
"date" => "2017-01-28",
"weather" => "sunny",
"Temp" => "12",
],
],
}
PS: To get the array version of this collections just attach ->all() at the end.
You can check in the Collections documentation a good explanation of the chunk() and mapSpread() methods as well of the rest of the available methods.
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 have a COLLECTION collflokks in MongoDB, sample Document is :-
{
"_id" : "b_8AUL",
"f_name" : "Pizza. Hut",
"f_lat" : "22.7523513",
"f_lng" : "75.9225847",
"c_uid" : "33",
"f_type" : NumberLong(3),
"members" : [
"42",
"43"
]
}
Within the "members" array , I want to add Arrays like {id:42,name:Mark} , {id:43,name:Hughes}
Currently i'm adding just ids(eg.42,43). I'm only concerned about the new data as it will have new ids .Please suggest.
Earlier I was using this code to push into the members Array:
$flokkCollection = 'collFlokks';
$flokkCollection->update(
array("_id" => $f_handle),
array('$push' => array("members" => $u_id))
);
Well if what you are asking here is "replacing your existing data" then you need to "loop" the results from the collection and "replace" the array content that exists with your new format.
There are likely smarter ways to approach this, but you are not really giving us all the required information in your question, so I can only answer in the basic terms.
Presuming you have:
$required = array(
array(array("id" => "42"), array("name" => "Mark")),
array(array("id" => "43"), array("name" => "Hughes"))
);
As input, then you do something like this:
function myMapper($v) {
return $v["id"];
}
$mapped = array_map("myMapper",$required);
foreach( $mapped as $value) {
$filtered = array_values(
array_filter($required,function($k) {
return $k["id"] == $value;
})
)[0];
collection.update(array(
array("members" => $value),
array('$set' => array(
"members.$" => $filtered
))
));
}
Which should use the positional $ operator to find the matched "position" of the array element by the value used in the "query" portion of the update statement, then in the "update" portion of that statement $set that current array index to the new value at the "filtered" content index from the original input array.
Outside of PHP. We call these inner elements "objects" and not "arrays" which is a PHP notation trait. Key/value things are "objects" and "lists" are "arrays".