I'm loading a json file where there's an object data, which has properties that are only integers.
They begin with 1000 then increment until 9999. Everything is ok. The problem comes with the properties 10000 and higher. When I load the file using json_decode(file_get_contents('myjsonfile')), if I try to do a foreach loop I have all the properties that begin with 1000 first, so this includes all the properties 10000 then I have other ones (2000, 3000, and so on).
The actual problem is that I need to keep the keys (because the properties are objects that sometimes contain link to keys of the "base" data object).
How can you make a working foreach loop with keys ordered asc?
I did this using a temporary table to sort key with SORT_NATURAL then foreach on it:
$tmp=array();
foreach ($obj as $key=>$item) {
$tmp[$key]=$item;
}
$tmp=(array_keys($tmp));
sort($tmp, SORT_NATURAL);
foreach ($tmp as $key) {
$item=$obj->$key;
/* ... my other code, with a good iteration ... */
}
Since JSON array keys are strings, that's why you get array sorted automatically.
Use ksort function first:
$array = (array) json_decode(json_encode(array("3000" => "Third", "10000" => "Fourth", "2000" => 'Second', "1000" => 'First')));
ksort($array, SORT_NUMERIC);
foreach ($array as $k => $v) {
var_dump($k, $v); echo "<br/>";
}
Related
I have the following array:
$array = array(
array("2018","2019"),
"Jan",
array("France","Germany")
);
I need a matrix that crosses all the elements of the array; e.g:
array(
array("2018","Jan","France"),
array("2018","Jan","Germany"),
array("2019","Jan","France"),
array("2019","Jan","Germany")
);
meaning, 2 x 2 x 1 arrays
but this can be that I have more elements that are or are not arrays then:
$array = array(
array("2018","2019"),
"Jan",
array("France","Germany"),
array("prod1","prod2","prod3"),
'Act'
);
In this case I would get 2 x 2 x 1 x 4 x 1 arrays in the end.
Any idea on how to achieve this?
Is that what you are looking for ?
$dst = array(array());
foreach ($array as $idx => $val) {
foreach ($dst as $tmp_idx => $tmp_array) {
if (is_array($val)) {
foreach ($val as $sub_idx => $sub_val) {
$dst[] = array_merge($dst[$tmp_idx], array(count($dst[$tmp_idx]) => $sub_val));
}
} else {
$dst[] = array_merge($dst[$tmp_idx], array(count($dst[$tmp_idx]) => $val));
}
unset($dst[$tmp_idx]);
}
}
I declare the array with an empty array in it.
A first foreach iterates through the main array to access all the categories, whatever their number.
A second foreach iterates through the result array.
A third foreach - or not, depending if the category contains several or a single entry - iterates through each entry of the current category and merges an array containing only that current category in the result currently iterated on (from $dst). The merge is pushed into the result array. The result stored in $dst are assumed to be temporary and will be copied and completed with each new value, making them progressively contain one entry from each category.
At the end of each iteration on $dst, the current temporary result is removed from the array since it has no purpose : if the foreach iterated on it, that means that it was incomplete.
At the end, the only entries in $dst that remain are these who weren't iterated on, meaning that every entry from each category were considered when they were created, meaning that they are complete.
I'm available for any clarification may the need arise.
I am using simplepie to get some feeds, I have set the key in the array which I am having trouble accessing. Here's my code:
$feed->set_feed_url(array(
'Title One'=>'http://example.com/rss/index.xml',
'Title Two'=>'http://feeds.example.com/rss/example',
'Title Three'=>'http://feeds.example.com/ex/blog'
));
When I loop over and try to access it I'm getting errors, here's how I am trying to access it.
foreach ($feed->get_items() as $item):
echo $item[0];
Fatal error: Cannot use object of type SimplePie_Item as array
How can I access those I tried also:
echo $item->[0];
without luck.
When you loop over an array (often used with associative arrays) using foreach, there is an additional construct to be able to get the key. It looks like this:
foreach ($feed->get_items() as $key => $item) {
echo($key);
}
So an array with a structure like:
$myArray = [
'a' => 1,
'b' => 2,
];
When iterated with foreach in that syntax, will put "a" or "b" in the $key variable depending on which iteration it is, and $item will contain either "1" or "2".
In your case, $item is the object instance and then you are trying to access it like it is an array. If you need to know the key, use that other foreach syntax.
To get the title of the SimplePie_Item object, you can call get_title():
foreach ($feed->get_items() as $index => $item) {
echo($item->get_title());
}
I have produced an array of fruits stored somewhere. Say it looks like this
$myFruits = array("apples"=>1, "oranges"=>3, "bananas"=>5);
This array is then passed into a function that will return json-encoded data for an API.
First, I wanted to be able to return a list of all the types of fruits I have
{"fruits":["apples", "oranges", "bananas"]}
I used this to accomplish it
echo json_encode(array("scripts" => array_keys($scripts)));
Now, I would like each type of fruit to be contained in its own hash, as such
{"fruits":
[
{name: "apples"
},
{name: "oranges"
},
{name: "bananas"
]
}
This way I can add additional fields to each fruit object without breaking existing code that may be using previous versions of this API (eg: if I decided to add the fruit counts in there as well).
Seeing how I can just create a new array and assign my list of fruits to a key called "fruits", I tried to do the same for each inner hash:
$myFruits = array("apples"=>1, "oranges"=>3, "bananas"=>5);
$data = array();
foreach ($myFruits as $key => $value) {
// initialize an associative array for each fruit
$val = array();
array_push($val, array("name" => $key));
// add it to the list of fruits
array_push($data, $val);
}
// assign list of fruits to "fruits" key
$outData = array("fruits" => $data);
echo json_encode($outData);
But I get this instead
{"fruits":[[{"name":"apples"}],[{"name":"oranges"}],[{"name":"bananas"}]]}
There are extra square braces around each fruit hash, which I assume is because I'm using an array to store each key-value pair.
How would I get my desired output?
You're close to knowing what you're doing wrong. You're creating an array, and then just using it to add one item (another array) to it.
// initialize an associative array for each fruit
$val = array(); // this guy here is unnecessary!!
array_push($val, array("name" => $key));
// add it to the list of fruits
array_push($data, $val);
Instead, just push each individual array onto $data directly like this:
array_push($data, array("name" => $key));
DEMO
You are creating an extra level in your array, simply push a new array onto $data in each iteration:
foreach ($myFruits as $key => $value) {
$data[]=array("name" => $key, "count" => $value);
}
*edited as per your comment
Taking a dictionary as an example, let's say I've got the following array to catalog the pronunciations of a given word:
$pronunciation["text"] = array("alpha", "beta", "gamma", "delta", "epsilon");
$pronunciation["definition"] = array(1, 2, NULL, NULL, 1);
text contains the pronunciation that will be displayed to the user, while definition contains the ID for the definition in the list where that pronunciation applies. If definition is NULL, it's not associated with any particular definition, and should be displayed elsewhere in the entry.
Now, if I try to do something like the following:
$key = array_search(1, $pronunciation["definition"]);
All I'll get is 0, since that's the first key in definition that contains the value. Likewise, substituting NULL returns 3, however both of these actually have another related key that I'm trying to fetch.
Is there a way to get it to return all related keys without having to resort to brute force methods such as a for loop?
Try this one:
array_keys($pronunciation["definition"],1)
I'm afraid there is not a function that do that as you want. Edit: Nope, there is! See Jauzsika answer.You have to use a foreach or a for loop.
function array_search_all($needle, $haystack) {
$keys = array();
foreach ($haystack as $k => $v) if ($v === $needle) $keys[] = $k;
return $keys;
}
Call:
$keys = array_search_all(1, $pronunciation["definition"]);
I don't know wheter it's faster or not, but I think if there're a set of data which you have to search in, it's better to set up an array, where the data is the key.
$data["alpha"] = 1
$data["beta"] = 1
//...
All your foreach should be modified from
foreach ($data as $item) {
to
foreach ($data as $item => $value) {
Restructure your arrays into a single array keyed on the text and using the definition as the value:
$pronunciation = array("alpha" => 1,
"beta" => 2,
"gamma" => NULL,
"delta" => NULL,
"epsilon" => 1);
Then use array_filter() to build a subset of the values you need
$searchVal = 1;
$subset = array_filter($pronunciation,
create_function('$value', 'return $value == '.$searchVal.';')
);
var_dump($subset);
If from a function I am returned a multidimensional array like this..
array(0 => array('a' => 5), 1 => array('a' => 8))
But I just really need the contents of the key 'a' what is the best way for me to convert.
Current I have been doing something like..
$new_array = array();
foreach ($multi_array AS $row) {
$new_array[] = $row['a']
}
without foreach:
$array = array(0 => array('a' => 1), 1 => array('a' => 8));
$new_array = array_reduce($array, function ($result, $current) {$result[]=current($current); return $result;}, array());
If that is all your requirements are, I think that is the best way. Anything else will have the same processing. Even after looking through the Array functions, I would say that this would be the best way. You can, however, make it a function to make it a bit more versatile:
$array = array(0 => array('a' => 1), 1 => array('a' => 8));
$new_array = flatten($array, 'a');
function flatten($array, $index='a') {
$return = array();
if (is_array($array)) {
foreach ($array as $row) {
$return[] = $row[$index];
}
}
return $return;
}
But yea, I would say what you have would be the most efficient way of doing it.
You Can Try As Like Following ......
$multi_array = array(0 => array('a' => 5), 1 => array('a' => 8));
$new_array = array();
foreach ($multi_array AS $key => $value) {
$new_array[] = $value['a'];
}
I recently found myself facing this problem, and I believe I have found the solution.
I will go over the problem itself, and also the solution, trying to explain everything along the way.
The problem was that I didn't have a two-dimensional array, but an array which could have any number of arrays inside arrays, so the solution by Brad F Jacobs couldn't apply here, although it's very simple and functional.
I had to work with a self-referencing database table called 'webpage', where one of the columns was 'parentWebpageId', which referenced an Id of some other row in that same table. This way, a tree structure can be built and easily managed, if you get your loops right.
Ia easily made a function which is supposed to generate a multi-dimensional array from one-dimensional self-referencing array, but the problem arose when I tried to make a function which should to the opposite. I needed this because if I wanted to delete a certain webpage, all it's children should also be deleted, in order to preserve the self-referential integrity.
It was easy to generate a tree whose root was the page that was initially to be deleted, but then I needed a list of all child webpage's Ids, in order to delete all of them.
So, the structure I had was something like this:
webpage1
id
title
...
childWebpageArray
webpage2
id
title
...
childWebpageArray
webpage2.1
id
url
...
childWebpageArray
webpage2.2
id
url
...
childWebpageArray
webpage2.2.1
id
url
...
childWebpageArray
webpage2.2.2
id
url
...
childWebpageArray
webpage2.3
id
url
...
childWebpageArray
webpage3
id
title
...
childWebpageArray
As you can see, the depth can go forever.
What I came up with is this:
function flattenMultidimensionalArray($multidimensionalArray) {
// Set anchor.
ohBoyHereWeGoAgain:
// Loop through the array.
foreach ($multidimensionalArray as $key1 => $value1) {
// Check if the webpage has child webpages.
if (isset($multidimensionalArray[$key1]["childWebpageArray"]) && (count($multidimensionalArray[$key1]["childWebpageArray"]) > 0)) {
// If it does, loop through all the child webpages, and move them into the initial multi-dimensional array.
foreach ($multidimensionalArray[$key1]["childWebpageArray"] as $key2 => $value2) {
$multidimensionalArray[] = $multidimensionalArray[$key1]["childWebpageArray"][$key2];
}
// Unset element's child pages, because all those child pages, along with their child pages
// have been moved into the initial array, thus reducing the depth of a multi-dimensional array by 1.
unset($multidimensionalArray[$key1]["childWebpageArray"]);
}
}
// Loop once again through the whole initial array, in order to check if any of the pages has children
foreach ($multidimensionalArray as $key => $value) {
// If a page which has children is found, kick the script back to the beginning, and go through it again.
if (isset($multidimensionalArray[$key]["childWebpageArray"]) && (count($multidimensionalArray[$key]["childWebpageArray"]) > 0)) {
goto ohBoyHereWeGoAgain;
}
}
// In the end, when there are no more pages with children, return an array of pages.
return $multidimensionalArray;
}
This solution worked in my case, and I believe is the right one for this kind of problem. It probably isn't much of a hassle to change it in order to fit your particular needs.
Hope this helps!