How to get next value in a multidimensional array - php

I am trying to produce a HTML list grouped by "groupName" from the array below.
array (size=30)
0 =>
array (size=4)
'groupOrder' => string '1' (length=1)
'groupName' => string 'Class' (length=11)
'txt' => string '............' (length=32)
'ID' => string '6' (length=1)
1 =>
array (size=4)
'groupOrder' => string '1' (length=1)
'groupName' => string 'Size' (length=11)
'txt' => string '..................' (length=34)
'ID' => string '6' (length=1)
2 =>
...
So I'd like produce something like this pseudo list:
groupName
txt
txt
txt
next GroupName
txt
txt
...
So my code looks like this
foreach ($datafeed as $val => $row) {
if (($datafeed[$val]['groupName']) == next($datafeed[$val]['groupName'])) {
//same group - do nothing
} else {
echo $datafeed[$val]['groupName'];
}
echo "<li>".$row['txt']. "</li>";
}
But I'm getting errors about "next() expects parameter 1 to be array, string given".
I've tried all sorts of different syntax, but I'm not making much progress. How do I compare two values in a nested array?

You misinterpreted the meaning of the function next(): you cannot query it for an array element. It manipulates the internal array pointer tied with the array itself, not with some its element. From the PHP documentation:
Every array has an internal pointer to its "current" element, which is initialized to the first element inserted into the array.
and see also a description of next.
Since the foreach loop crucially depends on the value of the array pointer, messing with the array pointer will ruin the loop: you probably see every second element in the loop, because at every iteration once next() is called by your foreach loop and then once by yourself.
The simplest thing for you is probably to use the old good for loop:
for ($i = 0; $i < length ($array); $i++)
{
if ($i == 0 || $array[$i] != $array[$i - 1])
echo "New group!\n";
echo $array[$i];
}

This doesn't answer your question directly, but you'd be better off restructuring your array so that they're grouped, and you don't need to perform any logic within the loop to check the groupName. Currently, you're relying on the next groupName to match the current groupName, but if they're not sequential, they won't be grouped.
You could do something like this:
$output = array();
foreach ($datafeed as $feed) {
$output[$feed['groupName']][] = $feed;
}
Here's a demo

You should not use next inside a foreach loop anyway, since you'll get conflicting array pointer movements. Simply store the last value:
$last = null;
foreach (...) {
if ($last != $row['current']) {
// new group
}
$last = $row['current'];
...
}

Related

Classify the values of an array in ascending order

I wish classify the values of my table in ascending order to be able to use them in a variable $distancecp.
My var_dump finds my values well but I can not classify them in ascending order.
$select100=mysqli_query($conn,$select10);
while($asso = mysqli_fetch_assoc($select100)) {
$distancecp1 = getDistance(''.$villeselect.', '.$cpselect.'',''.$asso['ville'].', '.$asso['codep'].'');
$distancecp2 = array($distancecp1);
var_dump($distancecp2);
foreach($distancecp2 as $distancecp) {
}
}
Results of var_dump($distancecp2) :
array (size=1)
0 =>
object(SimpleXMLElement)[8]
public 0 => string '68526' (length=5)
array (size=1)
0 =>
object(SimpleXMLElement)[10]
public 0 => string '71824' (length=5)
array (size=1)
0 =>
object(SimpleXMLElement)[7]
public 0 => string '67536' (length=5)
array (size=1)
0 =>
object(SimpleXMLElement)[9]
public 0 => string '33902' (length=5)
I tried :
$select100=mysqli_query($conn,$select10);
while($asso = mysqli_fetch_assoc($select100)) {
$distancecp1 = getDistance(''.$villeselect.', '.$cpselect.'',''.$asso['ville'].', '.$asso['codep'].'');
$distancecp2 = array($distancecp1);
asort($distancecp2);
foreach($distancecp2 as $distancecp){
echo ''.$distancecp.' ';
}
}
My echo returns me well my 4 values but not ranked in ascending order :(
Look carefully at your var_dump output: it's not printing a list of all your results, but is called multiple times, each time saying "array (size=1)". That "size=1" is your clue: you have a list with one thing in it, created with array($something). If you sort a list with one thing in it, you will just get the same list, with the same thing in it.
What you need to do instead is create one array for the whole loop, and add all the items to it:
$results = array();
while ( ... ) {
$distancecp1 = ...
$results[] = $distancecp1;
}
var_dump($results);
Then:
see here for appropriate sorting methods: How can I sort arrays and data in PHP?
to turn a SimpleXMLElement object into just a value, you write (string)$element

Explode string with two different separators to create multidimensional array

I have a string:
01;Tommy;32;Coder&&02;Annie;20;Seller
I want it like this:
array (size=2)
0 =>
array (size=4)
0 => string '01' (length=2)
1 => string 'Tommy' (length=5)
2 => int 42
3 => string 'Coder' (length=5)
1 =>
array (size=4)
0 => string '02' (length=2)
1 => string 'Annie' (length=5)
2 => int 20
3 => string 'Seller' (length=6)
Hope you can help me, thank you!
Not sure if the datatypes will be matching (as I believe it's all in a string) but here's the code
$myarray = array();
foreach(explode("&&",$mystring) as $key=>$val)
{
$myarray[] = explode(";",$val);
}
The explode command takes a string and turns it into an array based on a certain 'split key' which is && in your case
but since this is a dual array, I had to pass it through a foreach and another explode to solve.
It's very simple. First you need to explode the string by && and then traverse through array exploded by &&. And explode each element of an array by ;.
Like this,
<?php
$str="01;Tommy;32;Coder&&02;Annie;20;Seller";
$array=explode("&&",$str);
foreach($array as $key=>$val){
$array[$key]=explode(";",$val);
}
print_r($array);
Demo: https://eval.in/629507
you should just have to split on '&&', then split the results by ';' to create your new two dimensional array:
// $string = '01;Tommy;32;Coder&&02;Annie;20;Seller';
// declare output
$output = [];
// create array of item strings
$itemarray = explode('&&',$string);
// loop through item strings
foreach($itemarray as $itemstring) {
// create array of item values
$subarray = explode(';',$itemstring);
// cast age to int
$subarray[2] = (int) $subarray[2]; // only useful for validation
// push subarray onto output array
$output[] = $subarray;
}
// $output = [['01','Tommy',32,'Coder'],['02','Annie',20,'Seller']];
keep in mind that since php variables are not typed, casting of strings to ints or keeping ints as strings will only last depending on how the values are used, however variable type casting can help validate data and keep the wrong kind of values out of your objects.
good luck!
There is another appropach of solving this problem. Here I used array_map() with anonymous function:
$string = '01;Tommy;32;Coder&&02;Annie;20;Seller';
$result = array_map(function($value){return explode(';',$value);}, explode('&&', $string));

From CSV to array with headerkeys, now back to CSV

Our Story: (short version below if you're eager to troubleshoot)
This question is asked after extensively searching for a way to get a multidimensional array (with named keys) back into it's CSV file. You might say: "But this is covered on multiple pages on SO, search better!" but we did, and the results we found we have tried to bend to our will, but failed.
The reason for this in the first place was to remove columns from the CSV that were interfering with the rest of our Query's and Code.
So now we're back to ask on SO:
We've read the CSV into a multidimensional Array, using the headers' 1st line as key names.
We then used unset($array[$i]['insert_date']); to remove the columns from the array
We also str_replace'd those columns names from our $header variable.
So we're extensively reading out csv's, putting them in awesome Arrays that have a numerical first index, and second dimension keys named after the first line of our CSV file.
We also have the original Header from CSV file stored in a variable handsomely called $header with a string like: '"brand";"category";"category_path"
So.. $header is a string, $array is our multidimensional array.
All we want to do, and we're stuck editing loop after loop, is to create a brand new File, that has our $header as the first line, and our $array's values as strings..
file to write to: $putfile = fopen("feeds/broken/lu-zz.csv", "rw");
we're using: fputcsv($file, $array,';','"'); to write
and preferably: \n line endings
In short:
from this:
array (size=3886)
0 =>
array (size=19)
'brand' => string 'Tommy Hilfiger' (length=14)
'category' => string '' (length=0)
'category_path' => string 'Heren|Jeans|Blue jeans' (length=22)
1 =>
array (size=19)
'brand' => string 'Marc Aurel' (length=10)
'category' => string '' (length=0)
'category_path' => string 'Dames|Jurken|Zomerjurken' (length=24)
2 =>
array (size=19)
'brand' => string 'Rinascimento' (length=12)
'category' => string '' (length=0)
'category_path' => string 'Dames|Jurken|Print jurken' (length=25)
To This
"brand";"category";"category_path"
"Tommy Hilfiger";"";"Heren|Jeans|Blue jeans" (/n)
"Marc Aurel";"";"Dames|Jurken|Zomerjurken" (/n)
"Rinascimento";"";"Dames|Jurken|Print jurken" (/n)
Last piece of code we tried:
{
foreach($subarray as $value){
for ($i=0, $m=count($value); $i<$m; $i++){
//$test = implode('";"',$subarray) ;
//$tmp = array();
$result = call_user_func_array('array_merge', $subarray);
//$tmp[]= array_merge($subsub[$i]);
var_dump($result);
fputcsv($putfile, $subarray,';','"');
}
}
} fclose($putfile);
This just returns the same value over and over again into an array:
foreach ($array as $subarray) {
foreach($subarray as $value){
for ($i=0, $m=count($value); $i<$m; $i++){
//$test = implode('";"',$subarray) ;
//$tmp = array();
print_r($subarray);
fputcsv($putfile, $subarray,';','"');
}
}
} fclose($putfile);
Solution in our case: Thanks to "Don't Panic" & "CBroe".
$putfile = fopen("feeds/stukkefeeds/lu-zz.csv", "wb");
$header = str_replace('"','',$header1);
$titel = explode(';',$header);
var_dump($titel);
// then write in your data
fputcsv($putfile, $titel,';','"');
foreach ($array as $line) {
fputcsv($putfile, $line,';','"');
}
It looks like you may be making it more complicated than it needs to be. If you have an $array that is the one you've shown that looks like:
array (size=3886)
0 =>
array (size=19)
'brand' => string 'Tommy Hilfiger' (length=14)
'category' => string '' (length=0)
'category_path' => string 'Heren|Jeans|Blue jeans' (length=22)
...
And you have a working file handle that you've opened with
$putfile = fopen("feeds/broken/lu-zz.csv", "w");
You shouldn't need a nested loop at all. You can get the header line by using array_keys on the first item in the array (or any item, really), write it to the file with fputcsv, and then loop over the array and write each line of data, also with fputcsv.
$first_line = reset($array); // get the first line
fputcsv($putfile, array_keys($first_line)); // use its keys to write the headers
// then write in your data
foreach ($array as $line) {
fputcsv($putfile, $line,';','"');
}
Looks like you are thinking way too complicated here ...
$firstIteration = true;
foreach($yourArray as $elem) {
if($firstIteration ) { // if this is the first array element,
// write out its keys to create the CSV heading line
echo implode(';', array_keys($elem)) .'<br>';
$firstIteration = false;
}
echo implode(';', $elem) .'<br>'; // output the data for each array element
}
(Notice that I used echo and implode here for demonstration purposes; the result will not have the enclosing " - switching that out for writing CSV to the file again should be no issue.)

Filter a PHP array so that only unique records remain

I have this PHP array:
array (size=9753)
0 =>
array (size=3)
'brand' => string 'Brand #1' (length=8)
'name' => string 'Customer #13' (length=12)
'total' => string '93.00' (length=5)
1 =>
array (size=3)
'brand' => string 'Brand #1' (length=8)
'name' => string 'Customer #23' (length=12)
'total' => string '77.00' (length=5)
2 =>
array (size=3)
'brand' => string 'Brand #1' (length=8)
'name' => string 'Customer #32' (length=12)
'total' => string '98.00' (length=5)
...
I want to filter it so that only the record with the highest total value remains for every unique brand (there are 100 brands, in total). The result of the operation for this sample should be:
0 =>
array (size=3)
'brand' => string 'Brand #1' (length=8)
'name' => string 'Customer #32' (length=12)
'total' => string '98.00' (length=5)
...
as Brand #1 has the highest total
This is a matter of iterating over the whole array and leaving only one record for each Brand - the one with the highest total.
I've been trying my best, but didn't manage to achieve this. The code that I came up with is this:
$c = count($ordersData);
for($i=1; $i<$c; $i++) {
if($ordersData[$i]['brand'] == $ordersData[$i-1]['brand']
&& $ordersData[$i]['total'] > $ordersData[$i-1]['total']) {
unset($ordersData[$i-1]);
}
}
, but it does not remove all records that should be removed.
Suggestions are much appreciated.
So it seems like your best option is definitely to loop over all the records in $ordersData, as you've done. However, your logic is a bit wacky, and only compares the ordersdata total to the total of the previous order checked.
Instead, you'll likely want to start a new array, and add/overwrite values based on the brand name. Something like this, perhaps:
<?php
$results = array();
foreach($ordersData as $order) {
$brand = $order['brand'];
$total = $order['total'];
// If an order of this brand has already been tracked
if(array_key_exists($brand, $results)) {
// and the total of the current order is greater than what we have recorded
if($results[$brand]['total'] < $total) {
// Then let's replace it!
$results[$brand] = $order;
}
} else {
// Never added this brand before? Add it then
$results[$brand] = $order;
}
}
You can sort the array on total, ascending, then create a temp array indexed on brand (so that the key will get overwritten with later(higher) values), then use array_values to get numerically indexed array:
usort($array, function($a, $b) {
return $b['total'] - $b['total'];
});
$temp=[];
foreach($array as $element) $temp[$element['brand']]=$element;
$out = array_values($temp);
I've also come up with another method. I'm pasting it here just for reference (this is my initial attempt, improved).
$c = count($ordersData);
// Let's iterate through the whole array
for($i=0; $i<$c; $i++) {
// Save the current brand being checked
$currentBrand = $ordersData[$i]['brand'];
// If we can still check against the next record and the this is still the same brand..
if (key_exists($i+1, $ordersData) && $ordersData[$i]['brand'] == $ordersData[$i+1]['brand']) {
// If the next order value for the current brand is higher..
if ( $ordersData[$i]['total'] < $ordersData[$i+1]['total'] ) {
//Let's save/overwrite the higher order for the current brand
$results[$currentBrand] = $ordersData[$i+1];
}
}
}

PHP: Get array values based on conditions

I've been puzzling a lot with getting the correct values based on some conditions. First, let's look at what PHP's function var_dump() returned. This is just the important part in adjustment to the data I look for. Check the whole json object here.
array (size=3)
0 =>
array (size=12)
'inputs' =>
array (size=2)
0 =>
array (size=3)
'prev_out' =>
array (size=7)
'addr' => string '1AvY95SQqtWy6MKWZbE3Xnqant9F3whfPH' (length=34)
'value' => int 1583375
1 =>
array (size=3)
'prev_out' =>
array (size=7)
'addr' => string '1KEUVc2TxDh1VAcvrS5p3PtJHcRwzrvin1' (length=34)
'value' => int 150000
'out' =>
array (size=2)
0 =>
array (size=7)
'addr' => string '1Djp9h8mR3qqRz6v54nx265b8jZuqYNQ8j' (length=34)
'value' => int 1046166
1 =>
array (size=7)
'addr' => string '13W7N4NFwpTkYnHuVABcQfdrvDyszDqwkr' (length=34)
'value' => int 677209
What you just saw was the output of $data['txs']. The outer array is a list of transactions. Within each, the details are specified. The length of the "inputs" and "out" can change! I want to get the value of each transaction ($data['txs'][index of transaction]['out']['value']) that meets the following criteria:
The value of the "out" transaction should be bigger than zero.
The address of the "out" transaction should be equal to $address.
$address is not in the "inputs" transaction. E.g: $address can not be in the array of all ['inputs'][count(inputs)]['inputs']['prev_out']['addr'].
Here is my last attempt at solving this. The problem is that $result stays empty, even though the address 13W7N4NFwpTkYnHuVABcQfdrvDyszDqwkr is there and the result should be 677209.
$i = 0;
$txresult = array();
foreach($data['txs'] as $ct => $cv) {
$index = count($data['txs'][$i]['inputs']) - 1;
$addressindex = array();
for($testindex = 0; $testindex < $index; $testindex++) {
$addressindex[] = $data['txs'][$i]['inputs'][$index]['prev_out']['addr'];
}
$counter = count($data['txs'][$i]['out']) - 1;
for($count = 0; $count < $counter; $count++) {
if ($data['txs'][$i]['out'][$count]['value'] > 0 && $data['txs'][$i]['out'][$count]['addr'] == $address && !in_array($address, $addressindex)) {
$result = $data['txs'][$i]['out'][$count]['value'];
}
}
$i++;
}
Remember I cut the scope of the code, so it's possible some suggestions that require too much change may not work. I will do my best to respond to your questions asap.
Figured it out on my own terms. #Wrikken was instrumental to come to a conclusion.
The solution was pretty easy. Only two things:
$i++ shouldn't be in any of the for-loops, so I put it at the end of the foreach loop.
I had to unset $addressindex, $counter and $index.

Categories