Confused with foreach and multidimensional array - PHP - php

Ok, so arrays are my weakness and I'm struggling with this. It's probably dead simple too. Basically, I have an array which is
Code:
Array
(
[data] => Array
(
[0] => Array
(
[name] => getalbum
[fql_result_set] => Array
(
[0] => Array
(
[aid] => 187046464639937_101906
[name] => photo tab
[cover_pid] => 187046464639937_1661168
)
[1] => Array
(
[aid] => 187046464639937_99627
[name] => Cover Photos
[cover_pid] => 187046464639937_1661054
)
)
)
[1] => Array
(
[name] => getcover
[fql_result_set] => Array
(
[0] => Array
(
[src] => http://photos-g.ak.fbcdn.net/hphotos-ak-prn1/526499_403098366368078_187046464639937_1661168_217706037_s.jpg
)
[1] => Array
(
[src] => http://photos-b.ak.fbcdn.net/hphotos-ak-ash3/562470_403049039706344_187046464639937_1661054_361917190_s.jpg
)
)
)
)
)
I'm using a foreach to call the array by using
PHP Code:
foreach($fql_query_obj['data'] as $albums){
foreach($albums['fql_result_set'] as $album){
//print_r($album);
if ( ($album['name'] != "Wall Photos")
&& ($album['name'] != "Cover Photos")
&& ($album['name'] != "photo tab"))
{
echo $album['name'].' :: '.$album['aid'];
echo '<img src="'.$album['src'].'" /><br />';
}
}
}
Now it seems to go through the getalbum array then the getcover. How can I do it so it merges both of them together?

How do you get your data, some kind of database? Maybe you can merge it when you fetching that data?
Anyway, if your data is always ordered that way (matching arrays, one with first part of data, second with additional) how about something like that?
foreach($fql_query_obj['data'][0]['fql_result_set'] as $key_album => $album){
//print_r($album);
if ( ($album['name'] != "Wall Photos")
&& ($album['name'] != "Cover Photos")
&& ($album['name'] != "photo tab"))
{
echo $album['name'].' :: '.$album['aid'];
echo '<img src="'.$fql_query_obj['data'][1]['fql_result_set'][$key_album]['src'].'" /><br />';
}
}

It seems like you're trying to iterate the queries (getalbum and getcover). Instead, you probably want to iterate the albums and treat the cover and album data as a unified thing. I would try restructuring the data to be easier to work with:
list($albumsQuery, $coversQuery) = $fql_query_obj['data'];
$albums = array();
foreach ($albumsQuery['fql_result_set'] as $album) {
$albums[] = $album;
}
for ($i = 0, $numAlbums = count($albums); $i < $numAlbums; ++$i) {
$albums[$i] = array_merge($albums[$i], $coversQuery['fql_result_set'][$i]);
}
foreach ($albums as $album) {
// Here, $album contains data from both arrays
}
Note that this assumes there are no conflicting keys (there aren't in your example data), and there are lots of other ways to do this.

Related

Move elements in multidimensional array

I decoded XML document to an array via a json string like this:
$xmldoc =
'<music genre="electronic">
<festival name="Berlin">
<concert status="Not Started" date="24.03.2017">
<organizers>
<person name="V. Smith" id="130171"/>
</organizers>
</concert>
</festival>
</music>';
$xml = simplexml_load_string($xmldoc);
$json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence',json_encode($xml,true));
$array = json_decode($json,TRUE);
However, the elements with attributes were created with another "#attributes" layer like this:
Array
(
[#attributes] => Array
(
[genre] => electronic
)
[festival] => Array
(
[#attributes] => Array
(
[name] => Berlin
)
[concert] => Array
(
[#attributes] => Array
(
[status] => Not Started
[date] => 24.03.2017
)
[organizers] => Array
(
[person] => Array
(
[#attributes] => Array
(
[name] => V. Smith
[id] => 130171
)
)
)
)
)
)
How can I remove the "#attributes" layer, so that the resulting array looks like this instead:
Array
(
[genre] => electronic
[festival] => Array
(
[name] => Berlin
[concert] => Array
(
[status] => Not Started
[date] => 24.03.2017
[organizers] => Array
(
[person] => Array
(
[name] => V. Smith
[id] => 130171
)
)
)
)
)
I tried recursively traversing the array, and I can find the "#attributes", but then I'm having difficulty moving that section one dimension up to get rid of the "#attributes" layer.
Thank you.
Try below solution:
<?php
$xmldoc =
'<music genre="electronic">
<festival name="Berlin">
<concert status="Not Started" date="24.03.2017">
<organizers>
<person name="V. Smith" id="130171"/>
</organizers>
</concert>
</festival>
</music>';
$xml = simplexml_load_string($xmldoc);
$json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', 'replace_unicode_escape_sequence',json_encode($xml,true));
$array = json_decode($json,TRUE);
function removeSpecificKey(&$desired_array, $actualArray, $key_to_remove)
{
if (is_array($actualArray)) {
foreach ($actualArray as $key => $map) {
if ($key !== $key_to_remove) {
$desired_array[$key] = array();
removeSpecificKey($desired_array[$key], $actualArray[$key], $key_to_remove);
} else {
removeSpecificKey($desired_array, $actualArray[$key], $key_to_remove);
}
}
} else {
$desired_array = $actualArray;
}
}
$desired_array = array();
removeSpecificKey($desired_array, $array, '#attributes');
print_r($desired_array);
Output:
Array
(
[genre] => electronic
[festival] => Array
(
[name] => Berlin
[concert] => Array
(
[status] => Not Started
[date] => 24.03.2017
[organizers] => Array
(
[person] => Array
(
[name] => V. Smith
[id] => 130171
)
)
)
)
)
I'm going to start by saying to you what I say to everyone using more and more convoluted ways of abusing SimpleXML and json_encode - why do you need this? Take a step back, and think about what you're going to use this array for, and why you can't just use SimpleXML itself. Look at the examples in the manual for how you could.
For instance, you want to list the organizers of each festival? Then you'd loop over like this:
$xmldoc =
'<music genre="electronic">
<festival name="Berlin">
<concert status="Not Started" date="24.03.2017">
<organizers>
<person name="V. Smith" id="130171"/>
</organizers>
</concert>
</festival>
</music>';
$xml = simplexml_load_string($xmldoc);
foreach ( $xml->festival as $festival ) {
echo '<h2>', (string)$festival['name'], '</h2>';
echo '<ul>';
foreach ( $festival->concert as $concert ) {
foreach ( $concert->organizers->person as $organizer ) {
echo '<li>', (string)$organizer['name'], '</li>';
}
}
}
If you still think an array that throws away half the structure of the XML is what you want, then use SimpleXML to create it:
function turn_simplexml_into_broken_array($element) {
// Handle elements with text content
// By the way, this will break if the element has text content
// as well as children or attributes. So will the JSON hack.
// Because XML doesn't fit neatly in an array.
$text_content = trim( (string)$element );
if ( strlen($text_content) > 0 ) {
return $text_content;
}
$array = [];
foreach ( $element->attributes() as $name => $value ) {
$array[$name] = (string)$value;
}
foreach ( $element->children() as $name => $value ) {
// Handle multiple child elements with the same name
// Of course, this means the structure will be different
// for concerts with one organizer that concerts with multiple
// which leaving the object as SimpleXML would have saved you from
if ( count($element->{$name}) > 1 ) {
$array[$name][] = turn_simplexml_into_broken_array($value);
}
else {
$array[$name] = turn_simplexml_into_broken_array($value);
}
}
return $array;
}
$xml = simplexml_load_string($xmldoc);
print_r(turn_simplexml_into_broken_array($xml));
Note that we're not "removing #attributes" here. We're taking the XML attributes, and putting them into an array, along with the child elements.
Obviously, you can hack around with this to better suit the particular XML you're working with, and the structure you want. At which point, ask yourself again why you need a generic function for this at all.

Read the categories and subcategories in csv format and prepare multidimensional array

In the PHP, I need to convert the below image CSV file in this array format:
This code for creating categories and subcategories. If client will add the extra categories and subcategories its need to work as per that. So I need the dynamic one.
Array Format :
Array
(
[0] => Cateory1
[Cateory1] => Array
(
[0] => SubCategory11
[1] => SubCategory12
[2] => SubCategory13
[3] => SubCategory14
)
[1] => Cateory2
[Cateory2] => Array
(
[0] => SubCategory21
[1] => SubCategory22
[2] => SubCategory23
[SubCategory23] => Array
(
[0] => SubCategory221
[1] => SubCategory222
)
[3] => SubCategory24
)
[2] => Cateory3
[Cateory3] => Array
(
[0] => SubCategory31
[1] => SubCategory32
[2] => SubCategory33
)
[3] => Cateory4
[Cateory4] => Array
(
[0] => SubCategory41
[SubCategory41] => Array
(
[0] => SubCategory411
[SubCategory411] => Array
(
[0] => SubCategory4111
[SubCategory4111] => Array
(
[0] => SubCategory41111
)
)
)
)
)
Kindly help me to achieve this one.
Thanks.
Although i agree with Pitchinnate, I had some spare time and I hate parsing that sort of csv rubbish, so I thought I give it a try. Here is a piece of code that might get you going. I did not test or optimize anything, so if this doesn't work as expected, it might still point you in the right direction.
// I assume, $imput is a twodimensional array containing the csv data
// the multi dimensional result array
$result = array();
// accumulated categories of current-1 line
$lastCat = array();
foreach($input as $line) {
// accumulated categories of current line
$cat = array();
//First we create an array in $cat that contains the full "breadcrumbs" per line e.g.
// ['category1', 'SubCategory11', 'SubCategory114', ...]
$marker = PHP_INT_MAX;
for ($i=0; $i<count($line); $i++) {
if ($marker < $i) {
$cat[$i] = '';
} else if ($line[$i] != '') {
$cat[$i] = $line[$i];
$marker = $i;
}
}
// then using these category breadcrumbs, we create the result arrays
// you could do this using recursion if you want
$tmp = $result;
for ($i=0; $i<count($cat); $i++) {
// if we haven't seen this category yet, create it
// a bit bulky, but necessary as you want the categories with numeric indices as well
if (!isset($lastCat[$i]) || $cat[$i] != $lastCat[]) {
$tmp[] = $cat[$i];
// Check if there are still subcategories left in this line...
if (!empty($cat[$i+1])) {
//... and if so, create the category named index if not already existing
if (!array_key_exists($cat[$i], $tmp)) {
$tmp[$cat[$i]] = array();
}
$tmp = $tmp[$cat[$i]];
} else {
// ... and if not, we are finished with this line
break;
}
}
}
$lastCat = $cat;
}

PHP count null or 'new' elements within array

My array is below. What I am trying to do is count the number of nodes in the array have null or 'new' for read_status.
Is there something more sufficient than looping through the array?
Array
(
[0] => Array
(
[id] => 428
[read_status] =>
)
[1] => Array
(
[id] => 427
[read_status] =>
)
[2] => Array
(
[id] => 441
[read_status] => new
)
[3] => Array
(
[id] => 341
[read_status] => read
)
)
So the count should be 3.
you could do
$count = count(array_filter($myArray, function($item){
return $item['read_status'] != 'new';
}));
echo $count;
but I think its more efficient to just loop through it like this:
$count = 0;
foreach($myArray as $item){
if($item['read_status'] != 'new')$count++;
}
echo $count;
There is nothing wrong with looping in the array to do this, it might actually be faster than using a generic method to do it for you. It's simply this :
$count = 0;
foreach ($arrays as $entry)
{
if (!$entry['read_status'] || $entry['read_status'] === "new")
{
$count++;
}
}
echo $count;
I actually improved my SQL by removing the null completely -- so now read_status is either read or new.
IF(feed_read.read_status IS NULL,'new','read') AS read_status
From there, I was able to utilize another SO question in order to count the 'new' elements.
$counted = array_count_values(array_map(function($value){return $value['read_status'];}, $result));
echo $counted['new'];

How to get rid of the indexed count of arrays within an array in PHP

Hello I have an array that consists of two other arrays within it using the following code:
foreach($relations as $rel){
$data[$i]["relationTo"] = $rel["name"];
$data[$i]["relation"] = $rel["relation"];
$i = $i+1;
}
foreach($relations as $rel){
$children[$i]["id"] = $rel["id2"];
$children[$i]["name"] = $rel["sname"];
$children[$i]["data"] = $data;
$i = $i+1;
}
foreach($relations as $rel){
$relationArray[$i]["id"] = $rel["id"];
$relationArray[$i]["name"] = $rel["name"];
$relationArray[$i]["children"] = $children;
$i = $i+1;
}
When I print this out using:
print_r($relationArray);
It prints the following:
Array ( [2] => Array ( [id] => 4 [name] => Albaraa [children] =>
Array ( [1] => Array ( [id] => 5 [name] => Sadi [data] =>
Array ( [0] => Array ( [relationTo] => Albaraa [relation] => Father ) ) ) ) ) )
I am using json_encode and I need it to be output in json a certain way not including the indexed count of arrays in the beginning...the json output when I use:
echo json_encode($relationArray);
is like this currently:
{"2":{"id":"4","name":"Albaraa","children":
{"1":{"id":"5","name":"Sadi","data": [{"relationTo":"Albaraa","relation":"Father"}]}}}}
With the "2" and "1" in front of what the first 2 arrays are...which is not what I am trying to achieve which would be like this:
{"id":"4","name":"Albaraa","children":
{"id":"5","name":"Sadi","data": [{"relationTo":"Albaraa","relation":"Father"}]}}}}
Any help will be much appreciated!
Several solutions
1) Do not enter values by [$i], prepare new complete inner array and put it inside with array_push
2) If you still want to do this way you can extract just the values:
print_r(json_encode(array_values($array)));

most common values in a multidemensional array

My question is maybe repetitive but I really find it hard. (I have read related topics)
This is the array :
Array
(
[0] => Array
(
[legend] => 38440
)
[1] => Array
(
[bestw] => 9765
)
[2] => Array
(
[fiuna] => 38779
)
[3] => Array
(
[adam] => 39011
)
[4] => Array
(
[adam] => 39011
)
[5] => Array
(
[adam] => 39011
)
)
I have tried many ways to handle this array and find out the most common value. The result I expect is "adam"
$countwin = array_count_values($winnernames);
$maxwin = max($countwin);
$mostwinner = array_keys($countswin, $maxwin);
EDIT : My array is like this array("A"=>"1" , "B"=>"2" , "A"=>"1") it should return A is the most common
How about iterating your array and counting the values you've got?
$occurences = array();
foreach ($data as $row) {
foreach ($row as $key => $score) {
if (empty($occurences[$key])) {
$occurences[$key] = 1;
} else {
$occurences[$key]++;
}
}
}
and then sorting that
arsort($occurences);
and grabbing the first element of the sorted array
$t = array_keys($occurences);
$winner = array_shift($occurences);
You may try this code. A brute force method indeed. But a quick search made me to find this an useful one:
function findDuplicates($data,$dupval) {
$nb= 0;
foreach($data as $key => $val)
if ($val==$dupval) $nb++;
return $nb;
}
EDIT : Sorry, I misinterpreted your question! But it might be the first hint of finding the one with maximum counter.

Categories