robust way to traverse an array - php

I had the data in XML file i.e.
<domain>
<host>xyz</host>
<key>keeeeeeeeeey</key>
</domain>
<domain>
<host>xyz</host>
<key>keeeeeeeeeey</key>
</domain>
From that xml I created an array for robustness had I knew how to find that using xml I would have done so but lack of my knowledge I converted that xml file into array using:
$json = json_encode($xml);
$array = json_decode($json,TRUE);`
Below is my array:
Array
(
[domain] => Array
(
[0] => Array
(
[host] => bdbdfbdvbdbdfbdfbf.net
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
[1] => Array
(
[host] => bdev1vvvvvvveinf.net
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
[2] => Array
(
[host] => bdev1.aaaaaaaaureinf.net
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
[3] => Array
(
[host] => bdennnnnnnninf.net
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
[4] => Array
(
[host] => bdeveewerwerwerwerreinf.net
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
)
)
I want a robust loop through which if I pass the host name it returns the key. Can anyone please throw some light? The size of the array could grow to 100 000 000 plus entries.

Change your array to look like:
$data = array('domain' => array(
'bdbdfbdvbdbdfbdfbf.net' => '933...',
'bdev1vvvvvvveinf.net' => '933...',
));
Then you can do this:
echo $data['domain']['bdbdfbdvbdbdfbdfbf.net'];
There is no "robust" way to do it with your current array. You'd have to search through the entire thing:
function get_key($data, $host)
{
foreach ($data['domain'] as $domain)
{
if ($domain['host'] == $host)
return $domain['key'];
}
}
Given this new information:
The size of the array could grow to 100 000 000 plus entries.
I retract the usefulness of this answer, as the entire concept of using any plain text format, including XML or a serialized PHP key-value array, to store this amount of data is just crazy.
You should store the data in a database with the domain indexed. Even an sqlite database would be a major upgrade from a linear probe of a text file.
Of course there are ways to store the data in a custom format that is optimized, but there's really no good reason to reinvent something a database can easily do.

If possible, I think it would be better if host could be in place of the array key instead of a numeric index. That means it could look like
Array
(
[domain] => Array
(
[bdbdfbdvbdbdfbdfbf.net] => Array
(
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
[bdev1vvvvvvveinf.net] => Array
(
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
[bdev1.aaaaaaaaureinf.net] => Array
(
[key] => 933f416350de1a955544b30b5bb7ca09cfa2311101a22972320cc4c7af2ecedc03f36b8a48961ef938972478592a1e261819052b51c09a45cf805663f83cb2c0233969255a2c3e2e7e212a295a247b785d41
)
)
)
which would be searchable with
$somedomain = "bdev1.aaaaaaaaureinf.net";
if (isset($domains['domain'][$somedomain])) {
// do stuff
//$domains['domain'][$somedomain]['key']; is the key you want
}
If you can, do it that way

Since you only need the [domain] array from the outer array, this should work
function getKey($domains)
{
foreach($domains as $domain)
{
if($domain['host'] == $testHost)
return $domain['key'];
}
return false;
}
$myKey = getKey($myArr['domain']);

Here is a method that works with the array that you gave. You don't have to make any changes to the array.
/**
* Find the Key of the Domain in the Array with a Given Host
* #param $given The host you want to search for
* #returns The key of the domain (of the array) that has the matching host
*/
function findHost($given)
{
// This code assumes that the data array is $array .
global $array;
foreach ($array["domain"] as $key => $value)
{
if ($value["host"] == $given)
return $key;
}
// If no matches
return false;
}
// Call findHost() as you desire.
// If there is no match, the function returns false.
// Otherwise, it returns the key of $array["domain"] that the host matches.

With 100 000 000 plus entries you're likely hitting the string length limit in PHP which would mean that you can't use json_encode and json_decode any longer.
This does something similar, but you need to metric yourself what's faster:
$array = (array) $xml;
array_walk_recursive($array, function(&$v) { $v = (array) $v; });
Good luck!
Anyway, I wonder how large that XML string is then. Hmm. I think the numbers you give are just not right, your question looks pretty bogus on a second thought.

Related

how to get value from array with 2 keys

i have array like
Array
(
[1] => Array
(
[user_info] => Array
(
[id] => 1
[name] => Josh
[email] => u0001#josh.com
[watched_auctions] => 150022 150031
)
[auctions] => Array
(
[150022] => Array
(
[id] => 150022
[title] => Title of auction
[end_date] => 2013-08-28 17:50:00
[price] => 10
)
[150031] => Array
(
[id] => 150031
[title] => Title of auction №
[end_date] => 2013-08-28 16:08:03
[price] => 10
)
)
)
so i need put in <td> info from [auctions] => Array where is id,title,end_date but when i do like $Info['id'] going and put id from [user_info] when i try $Info[auctions]['id'] there is return null how to go and get [auctions] info ?
Try:
foreach( $info['auctions'] as $key=>$each ){
echo ( $each['id'] );
}
Or,
foreach( $info as $key=>$each ){
foreach( $each['auctions'] as $subKey=>$subEach ){
echo ( $subEach['id'] );
}
}
Given the data structure from your question, the correct way would be for example:
$Info[1]['auctions'][150031]['id']
$array =array();
foreach($mainArray as $innerArray){
$array[] = $innerArray['auctions'];
}
foreach($array as $key=>$val){
foreach($val as $k=>$dataVal){
# Here you will get Value of particular key
echo $dataVal[$k]['id'];
}
}
Try this code
Your question is a bit malformed. I don't know if this is due to a lacking understanding of the array structure or just that you had a hard time to explain. But basically an array in PHP never has two keys. I will try to shed some more light on the topic on a basic level and hope it helps you.
Anyway, what you have is an array of arrays. And there is no difference in how you access the contents of you array containing the arrays than accessing values in an array containing integers. The only difference is that what you get if you retrieve a value from your array, is another array. That array can you then in turn access values from just like a normal array to.
You can do all of this in "one" line if you'd like. For example
echo $array[1]["user_info"]["name"]
which would print Josh
But what actually happens is no magic.
You retrieve the element at index 1 from your array. This happens to be an array so you retrieve the element at index *user_info* from that. What you get back is also an array so you retrieve the element at index name.
So this is the same as doing
$arrayElement = $array[1];
$userInfo = $arrayElement["user_info"];
$name = $userInfo["name"];
Although this is "easier" to read and debug, the amount of code it produces sometimes makes people write the more compact version.
Since you get an array back you can also do things like iterating you array with a foreach loop and within that loop iterate each array you get from each index within the first array. This can be a quick way to iterate over multidimensional array and printing or doing some action on each element in the entire structure.

How to find the index number of an array that contains a certain key/value

(
[1] => Array
(
[rules_properties_id] => 1
[operator] => >=
[value] => 2
[function] => NumOrdersPlaced
[rules_properties_params] => Array
(
[num_days] => 30
[customer_id] => 5
)
)
[2] => Array
(
[rules_properties_id] => 1
[operator] => >=
[value] => 5
[function] => NumOrdersPlaced
[rules_properties_params] => Array
(
[num_days] => 90
[customer_id] => 5
)
)
[3] => Array
(
[rules_properties_id] => 2
[operator] => >
[value] => 365
[function] => CustAcctAge
[rules_properties_params] => Array
(
[customer_id] => 5
)
)
)
That's the print_r of an array that I'm getting back from my database. I need to find the index number of the sub-array that contains the function called NumOrdersPlaced (the expected result would be 2.) Is the only way to do this by looping through the array and subarrays and comparing (as in this answer)? Or is there a more efficient, elegant (i.e. one-liner) function available that I don't know about?
No, there is no one liner for searching multidimensional arrays in PHP, expect you'll write a function for it yourself and use it as one liner :)
Approaches would be:
Change the data structure to somewhat that is good for search operations. eg xml with xpath
When creating the array from your question, create another array which indexes are the function names, and which values are pointers to the sub arrays of the original array
Use the database for that operations. It's optimized for it
...
When searching for the 'right' way you'll have to find a compromise between performance of search, insert, update, remove operations, memory consumption and ease of usage.
As you asked for a PHP solution, here comes an example how I would do it in PHP using and additional index array: (approach 2. from the list above)
// we need two arrays now:
$data = array();
$index = array();
// imagine you loop through database query results
foreach($db_result as $record) {
// create a copy of $record as the address
// of record will contain the last(!) element agter foreach
$item = $record;
// store pointers to that array in data and index
$data []= &$item;
$index[$item->function] = &$item;
}
// here is your one liner
$found = isset($index['NumOrdersPlaced']) ? $index['NumOrdersPlaced'] : NULL;
// another index seach:
$found = isset($index['CustAcctAge']) ? $index['CustAcctAge'] : NULL;
// note there is no additonal loop. The cost is the
// additional memory for $index

PHP Array get each Key/Value from XML File

I'm getting stumped by simply trying to get the key/value of a certain tier inside an array I have created from an XML file. The part of the array from Print_R() is:
SimpleXMLElement Object
(
Array
(
[category] => SimpleXMLElement Object
(
[#attributes] => Array
(
[settings] => maximum
)
[cat_1] => 5.21
[cat_2] => 5.05
[cat_3] => 19.36
[cat_4] => 21.97
[cat_5] => 12.17
)
)
)
I am trying to get the "cat_1, cat_2, cat_3 .." keys so that I can put them in their own array and use them for other things. I can do print_r($array) and it works, but when I try and do this:
foreach ($array->category as $key => $val) {
$new_array[$key]= "$val";
}
$array->category doesn't seem to target that list. The "SimpleXMLElement Object" from the XML file seems to be in the way of how I normally use arrays. Does anyone know how I can get to those cat_1 ets. lists?
Notice that $array->category is an object, not an array and cat_* are properties. Since they are all public just use:
$new_array = get_object_vars($array->category);
You should convert simpleXML object to array using
$array = json_decode(json_encode((array) $simplexmlob)), 1);
Then use $array['category'] for other things. There is no need to use foreach loop.

Navigating a multidimensional array with dynamic

I'm trying to figure out why it is that I cannot access the follow array with this statement:
var_dump($thevar[0]['product_id']);
Array
(
[d142d425a5487967a914b6579428d64b] => Array
(
[product_id] => 253
[variation_id] =>
[variation] =>
[quantity] => 1
[data] => WC_Product Object
(
[id] => 253
[product_custom_fields] => Array
(
[_edit_last] => Array
(
[0] => 1
)
[_edit_lock] => Array
(
[0] => 1345655854:1
)
[_thumbnail_id] => Array
(
[0] => 102
)
I can, however, access the 'product_id' using the dynamically created array name:
print_r($thevar['d142d425a5487967a914b6579428d64b']['product_id']);
The issue is, I don't know what that dynamic name is going to be on the fly...
There are several options for such scenarios.
Manually iterate over the array
You can use reset, next, key and/or each to iterate over the array (perhaps partially).
For example, to grab the first item regardless of key:
$item = reset($thevar);
Reindex the array
Sometimes it's just convenient to be able to index into the array numerically, and a small performance hit is not a problem. In that case you can reindex using array_values:
$values = array_values($thevar);
$item = $values[0]; // because $values is numerically indexed
Iterate with foreach
This would work for a single value as well as it works for more, but it might give the wrong impression to readers of the code.
foreach($thevar as $item) {
// do something with $item
}
If the array key is dynamic you might find the PHP function array_keys() useful.
It will return an array of the keys used in an array. You can then use this to access a particular element in the array.
See here for more:
http://php.net/manual/en/function.array-keys.php
Because PHP array are associative therefor you have to access them by key.
But you may use reset($thevar) to get first item.
Or array_values():
array_values($thevar)[0]
Or if you feel like overkill you may also use array_keys() and use the [0] element to address element like this:
$thevar[ array_keys($thevar)[0]]

PHP - Create a single array from a multidimensional array based on key name

I know there are a lot of answers on multi-dimensional arrays but I couldn't find what I was looking for exactly. I'm new to PHP and can't quite get my head around some of the other examples to modify them. If someone could show me the way, it would be much appreciated.
An external service is passing me the following multidimensional array.
$mArray = Array (
[success] => 1
[errors] => 0
[data] => Array (
[0] => Array (
[email] => me#example.com
[id] => 123456
[email_type] => html
[ip_opt] => 10.10.1.1
[ip_signup] =>
[member_rating] => X
[info_changed] => 2011-08-17 08:56:51
[web_id] => 123456789
[language] =>
[merges] => Array (
[EMAIL] => me#example.com
[NAME] => Firstname
[LNAME] => Lastname
[ACCOUNT] => ACME Ltd
[ACCMANID] => 123456adc
[ACCMANTEL] => 1234 123456
[ACCMANMAIL] => an.other#example.com
[ACCMANFN] => Humpty
[ACCMANLN] => Dumpty
)
[status] => unknown
[timestamp] => 2011-08-17 08:56:51
[lists] => Array ( )
[geo] => Array ( )
[clients] => Array ( )
[static_segments] => Array ( )
)
)
)
The only information I'm interested in are the key/value pairs that are held in the array under the key name 'merges'. It's about the third array deep. The key name of the array will always be called merges but there's no guarantee that its location in the array won't be moved. The number of key/value pairs in the merges array is also changeable.
I think what I need is a function for array_walk_recursive($mArray, "myfunction", $search);, where $search holds the string for the Key name (merges) I'm looking for. It needs to walk the array until it finds the key, check that it holds an array and then (preserving the keys), return each key/value pair into a single array.
So, for clarity, the output of the function would return:
$sArray = Array (
[EMAIL] => me#example.com
[NAME] => Firstname
[LNAME] => Lastname
[ACCOUNT] => ACME Ltd
[ACCMANID] => 123456adc
[ACCMANTEL] => 1234 123456
[ACCMANMAIL] => an.other#example.com
[ACCMANFN] => Humpty
[ACCMANLN] => Dumpty
)
I can then move on to the next step in my project, which is to compare the keys in the single merges array to element IDs obtained from an HTML DOM Parser and replace the attribute values with those contained in the single array.
I probably need a foreach loop. I know I can use is_array to verify if $search is an array. It's joining it all together that I'm struggling with.
Thanks for your help.
Would this work?
function find_merges($arr)
{
foreach($arr as $key => $value){
if($key == "merges") return $value;
if(is_array($value)){
$ret = find_merges($value);
if($ret) return $ret;
}
}
return false;
}
It would do a depth-first search until you either ran out of keys or found one with the value merges. It won't check to see if merges is an array though. Try that and let me know if that works.
Here is a general purpose function that will work it's way through a nested array and return the value associated with the first occurance of the supplied key. It allows for integer or string keys. If no matching key is found it returns false.
// return the value a key in the supplied array
function get_keyval($arr,$mykey)
{
foreach($arr as $key => $value){
if((gettype($key) == gettype($mykey)) && ($key == $mykey)) {
return $value;
}
if(is_array($value)){
return get_keyval($value,$mykey);
}
}
return false;
}
// test it out
$myArray = get_keyval($suppliedArray, "merges");
foreach($myArray as $key => $value){
echo "$key = $value\n";
}
A recursive function can do this. Returns the array or FALSE on failure.
function search_sub_array ($array, $search = 'merges') {
if (!is_array($array)) return FALSE; // We're not interested in non-arrays
foreach ($array as $key => $val) { // loop through array elements
if (is_array($val)) { // We're still not interested in non-arrays
if ($key == $search) {
return $val; // We found it, return it
} else if (($result = search_sub_array($array)) !== FALSE) { // We found a sub-array, search that as well
return $result; // We found it, return it
}
}
}
return FALSE; // We didn't find it
}
// Example usage
if (($result = search_sub_array($myArray,'merges')) !== FALSE) {
echo "I found it! ".print_r($result,TRUE);
} else {
echo "I didn't find it :-(";
}
So you want to access an array within an array within an array?
$mergeArray = NULL;
foreach($mArray['data'] as $mmArray)
$mergeArray[] = $mmArray['merges'];
Something like that? If merges is always three deep down, I don't see why you need recursion. Otherwise see the other answers.
Here's another approach, mostly because I haven't used up my iterator quota yet today.
$search = new RegexIterator(
new RecursiveIteratorIterator(
new ParentIterator(new RecursiveArrayIterator($array)),
RecursiveIteratorIterator::SELF_FIRST),
'/^merges$/D', RegexIterator::MATCH, RegexIterator::USE_KEY
);
$search->rewind();
$merges = $search->current();
array_walk_recursive() is brilliant for this task! It doesn't care what level the key-value pairs are on and it only iterates the "leaf nodes" so there is not need to check if an element contains a string. Inside of the function, I am merely making a comparison on keys versus the array of needles to generate a one-dimensional result array ($sArray).
To be clear, I am making an assumption that you have predictable keys in your merges subarray.
Code: (Demo)
$needles=['EMAIL','NAME','LNAME','ACCOUNT','ACCMANID','ACCMANTEL','ACCMANMAIL','ACCMANFN','ACCMANLN'];
array_walk_recursive($mArray,function($v,$k)use(&$sArray,$needles){if(in_array($k,$needles))$sArray[$k]=$v;});
var_export($sArray);
Output:
array (
'EMAIL' => 'me#example.com',
'NAME' => 'Firstname',
'LNAME' => 'Lastname',
'ACCOUNT' => 'ACME Ltd',
'ACCMANID' => '123456adc',
'ACCMANTEL' => '1234 123456',
'ACCMANMAIL' => 'an.other#example.com',
'ACCMANFN' => 'Humpty',
'ACCMANLN' => 'Dumpty',
)

Categories