Trouble with adding to array in while loop - php

I have a while loop that uses the fgetcsv function and iterates through a csv file until the end. In the loop I want to add a value from a specific column to a new array.
Everything works as it echos the value from the column that I need. However when I put the line in to add to the array it does not work. I have a HTML table that prints after the PHP code however when I use the line to add to the array it does not work.
I have looked on the internet and everything I have seen is doing it the way I have done so I am a little confused.
Here is my code:
$amountRecords = 0;
$totalValue = 0;
$valueArray = array();
$handle = fopen('data.csv', 'r');
// to skip the header names/values
fgetcsv($handle);
while($row = fgetcsv($handle, "\r"))
{
$valueArray[$amountRecords] += $row[1]; // THIS IS THE LINE THAT IS NOT WORKING
$totalValue = $totalValue + $row[1];
$amountRecords++;
}

There is some strangeness with your code. You're incrementing $amountRecords each time, so you'll never access the same index in $valueArray twice, yet, you're adding values to each element. Possibly you simply mean to assign the value with $valueArray[$amountRecords] = $row[1]; instead of +=?
If that's the case, it looks like you're simply attempting to add the item onto the end of the array, extracting column 1 into its own array. You should use array_push or array[]= syntax for that:
while($row = fgetcsv($handle, "\r"))
{
// Add $row[1] to the end of $valueArray
$valueArray[] = $row[1];
$totalValue = $totalValue + $row[1];
}
The += operator is for adding something to an existing value. Typing a += b is the same as typing a = a + b. You should be using that operator on the next line, for example:
$totalValue += $row[1];
As a final suggestion, learn to do some basic debugging. If your loop isn't working, make it show you what it's doing during each iteration. Use var_dump to inspect your variables and make sure they actually contain what you think they contain. Using var_dump($row) would be especially useful in making sure that $row[1] is the correct index.
echo "Before loop\n";
while($row = fgetcsv($handle, "\r"))
{
echo '$row contains: ';
var_dump($row);
$valueArray[] += $row[1]; // THIS IS THE LINE THAT IS NOT WORKING
echo '$valueArray now contains ':
var_dump($valueArray);
$totalValue = $totalValue + $row[1];
}
echo "After loop\n";

From my understand of your script $valueArray[$amountRecords] += $row[1]; would not make any logical sense because its dependent on $amountRecords ++; which would always increase .
I think your script would work fine like this
while ( $row = fgetcsv($handle, "\r") ) {
$valueArray[] = $row[1]; // Put all Row[1] Into a array
$totalValue += $row[1]; // Sum total Value
$amountRecords ++; //Get Record Count
}

Related

PHP & CSV - Echo Result only once

i am fairly new to PHP and tried several hours to get something going, sadly without a result. I hope you can point me into the right direction.
So what i got is a CSV file containing Articles. They are separated into diff columns and always the same structure, for example :
ArtNo, ArtName, ColorCode, Color, Size
When an article has different color codes in the CSV, the article is simply repeated with the same information except for the color code, see an example:
ABC237;Fingal Edition;48U;Nautical Blue;S - 5XL;
ABC237;Fingal Edition;540;Navy;S - 5XL;
My problem is, i want to display all the articles in a table, include an article image etc.. so far i got that working which is not a problem, but instead of showing the article twice for every different color code i want to create only one line per ArtNo (First CSV Line) but still read the second duplicate line to add the article color to the first one, like :
ABC237; Fingal Edition ;540;Nautical Blue, Navy;S - 5XL;
Is this even possible or am I going into a complete wrong direction here? My code looks like this
<?php
$csv = readCSV('filename.csv');
foreach ($csv as $c) {
$artNo = $c[0]; $artName = $c[1]; $colorCode = $c[2]; $color = $c[3]; $sizes = $c[4]; $catalogue = $c[5]; $GEP = $c[6]; $UVP = $c[7]; $flyerPrice = $c[8]; $artDesc = $c[9]; $size1 = $c[10]; $size2 = $c[11]; $size3 = $c[12]; $size4 = $c[13]; $size5 = $c[14]; $size6 = $c[15]; $size7 = $c[16]; $size8 = $c[17]; $picture = $c[0] . "-" . $c[2] . "-d.jpg";
// Echo HTML Stuff
}
?>
Read CSV Function
<?php
function readCSV($csvFile){
$file_handle = fopen($csvFile, 'r');
while (!feof($file_handle) )
{
$line_of_text[] = fgetcsv($file_handle, 0, ";");
}
fclose($file_handle);
return $line_of_text;
}
?>
I tried to get along with array_unique etc but couldn't find a proper solution.
Read all the data into an array, using the article number as the key....
while (!feof($file_handle) ) {
$values = fgetcsv($file_handle, 0, ";");
$artno = array_shift($values);
if (!isset($data[$artno])) $data[$artno]=array();
$data[$artno][]=$values;
}
And then output it:
foreach ($data as $artno=>$v) {
$first=each($v);
print $artno . "; " . each($first);
foreach ($v as $i) {
$discard=array_shift($i);
print implode(";", $i);
}
print "\n";
}
(code not tested, YMMV)
You need to know exactly how many items belong to each ArtNo group. This means a loop to group, and another loop to display.
When grouping, I steal the ArtNo from the row of data and use it as the grouping key. The remaining data in the row will be an indexed subarray of that group/ArtNo.
I am going to show you some printf() and sprintf() syntax to keep things clean. printf() will display the first parameter's content and using any subsequent values to replace the placeholders in the string. In this case, the 2nd parameter is a conditional expression. On the first iteration of the group, ($i = 0), we want to show the ArtNo as the first cell of the row and declare the number of rows that it should span. sprinf() is just like printf() except it produces a value (silently). Upon any subsequent iterations of the group, $i will be greater than zero and therefore an empty string is passed as the value.
Next, I'm going to use implode() which is beautifully flexible when you don't know exactly how many columns your table will have (or if the number of columns may change during the lifetime of your project).
Tested Code:
$csv = <<<CSV
ABC237;Fingal Edition;48U;Nautical Blue;S - 5XL
ABC236;Fingal Edition;540;Navy;S - 5XL
ABC237;Fingal Edition;49U;Sea Foam;L - XL
ABC237;Fingal Edition;540;Navy;S - 5XL
CSV;
$lines = explode(PHP_EOL, $csv);
foreach ($lines as $line) {
$row = str_getcsv($line, ';');
$grouped[array_shift($row)][] = $row;
}
echo '<table>';
foreach ($grouped as $artNo => $group) {
foreach ($group as $i => $values) {
printf(
'<tr>%s<td>%s</td></tr>',
(!$i ? sprintf('<td rowspan="%s">%s</td>', count($group), $artNo) : ''),
implode('</td><td>', $values)
);
}
}
echo '</table>';
Output:

php not able to get array value

I have this problem where I can't get the value from the array in the for loop but I can access it in the while loop.
I can't seem to find a answer online, so help would be much appreciated.
while ($pos = strpos($logTxt, $char, $pos))
{
$t++;
$pos += strlen($char);
$positions[$t] = $pos;
}
for($i = 0; $i < sizeof($positions); $i++)
{
$beginLine = $lastEndLine;
$endLine = $positions[2];
$textToEcho = substr($logTxt,$beginLine,$endLine);
$lastEndLine = $endLine;
}
I think that this could be pretty easily fixed by using a foreach loop instead of a for loop, because it is an array.
foreach($positions as $position) {
$beginLine = $lastEndLine;
$endLine = $position;
$textToEcho = substr($logTxt,$beginLine,$endLine);
$lastEndLine = $endLine;
}
If you want to use a for loop still, I believe your problem is you are only referencing the 3rd position of the array (Key 2, as arrays start at 0), not what the loop is pointing to. You could fix it by doing this
for($i = 0; $i < sizeof($positions); $i++)
{
$beginLine = $lastEndLine;
$endLine = $positions[$i];
$textToEcho = substr($logTxt,$beginLine,$endLine);
$lastEndLine = $endLine;
}
Your $endLine always has third element from array, because of $positions[2]. Try changing it to $positions[$i]
You base problem is using constant index in $positions[2]. But your 1st line in for loop $beginLine = $lastEndLine; will always fail because $lastEndLine is not defined yet. You can use smth like
// beginLine // endLine
$textToEcho = substr($logTxt, $positions[$i-1], $positions[$i]);
of course you need $positions[-1] set to 0 before your first loop or smth like this (it's not clear what's happening before)
UPD I've tried your code and concluded
it will not work at all if $char is the first occurence in $logTxt
it does the nearly the same as explode() function

Basic PHP concepts (accessing/declaring array variables)

$result = array();
for ( $i = 10; $i < 101; $i = $i + 10 ){
$result[] = $i;
}
echo implode(", ", $result);
Hello...I'm new to PHP, and this really confused me, declaring a variable array even the code will work without it.
I've found this code here in the forum, regarding the removal of the comma in a for loop. I was wondering what variable is called when it is echoed? Is it the $result = array() or the $result[]? I've tried to remove the $result = array(); and the code still work, is that mean, is it ok to just remove the $result = array();? Does it have some coding issues if it is removed?
The line $result = array(); is used to declare an array.
It's a better approach to use this especially when you have some other previously specified variable $result storing some other value. Mentioning this first line will reset any previously assigned value to $result and declare it as an array datatype.
$result[] = $i; means the value of $i keeps apppending to $result every time.

Finding duplicate column values in a CSV

I'm importing a CSV that has 3 columns, one of these columns could have duplicate records.
I have 2 things to check:
1. The field 'NAME' is not null and is a string
2. The field 'ID' is unique
So far, I'm parsing the CSV file, once and checking that 1. (NAME is valid), which if it fails, it simply breaks out of the while loop and stops.
I guess the question is, how I'd check that ID is unique?
I have fields like the following:
NAME, ID,
Bob, 1,
Tom, 2,
James, 1,
Terry, 3,
Joe, 4,
This would output something like `Duplicate ID on line 3'
Thanks
P.S this CSV file has more columns and can have around 100,000 records. I have simplified it for a specific reason to solve the duplicate column/field
Thanks
<?php
$cnt = 0;
$arr=array();
if (($handle = fopen("1.csv", "r")) !== FALSE) {
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
$num=count($data);
$cnt++;
for ($c=0; $c < $num; $c++) {
if(is_numeric($data[$c])){
if (array_key_exists($data[$c], $arr))
$arrdup[] = "duplicate value at ".($cnt-1);
else
$arr[$data[$c]] = $data[$c-1];
}
}
}
fclose($handle);
}
print_r($arrdup);
Give it a try:
$row = 1;
$totalIDs = array();
if (($handle = fopen('/tmp/test1.csv', "r")) !== FALSE)
{
while (($data = fgetcsv($handle)) !== FALSE)
{
$name = '';
if (isset($data[0]) && $data[0] != '')
{
$name = $data[0];
if (is_numeric($data[0]) || !is_string($data[0]))
echo "Name is not a string for row $row\n";
}
else
{
echo "Name not set for row $row\n";
}
$id = '';
if (isset($data[1]))
{
$id = $data[1];
}
else
{
echo "ID not set for row $row\n";
}
if (isset($totalIDs[$id])) {
echo "Duplicate ID on line $row\n";
}
else {
$totalIDs[$id] = 1;
}
$row++;
}
fclose($handle);
}
I went assuming a certain type of design, as stripped out the CSV part, but the idea will remain the same :
<?php
/* Let's make an array of 100,000 rows (Be careful, you might run into memory issues with this, issues you won't have with a CSV read line by line)*/
$arr = [];
for ($i = 0; $i < 100000; $i++)
$arr[] = [rand(0, 1000000), 'Hey'];
/* Now let's have fun */
$ids = [];
foreach ($arr as $line => $couple) {
if ($ids[$couple[0]])
echo "Id " . $couple[0] . " on line " . $line . " already used<br />";
else
$ids[$couple[0]] = true;
}
?>
100, 000 rows aren't that much, this will be enough. (It ran in 3 seconds at my place.)
EDIT: As pointed out, in_array is less efficient than key lookup. I've updated my code consequently.
Are the IDs sorted with possible duplicates in between or are they randomly distributed?
If they are sorted and there are no holes in the list (1,2,3,4 is OK; 1,3,4,7 is NOT OK) then just store the last ID you read and compare it with the current ID. If current is equal or less than last then it's a duplicate.
If the IDs are in random order then you'll have to store them in an array. You have multiple options here. If you have plenty of memory just store the ID as a key in a plain PHP array and check it:
$ids = array();
// ... read and parse CSV
if (isset($ids[$newId])) {
// you have a duplicate
} else {
$ids[$newId] = true; // new value, not a duplicate
}
PHP arrays are hash tables and have a very fast key lookup. Storing IDs as values and searching with in_array() will hurt performance a lot as the array grows.
If you have to save memory and you know the number of lines you going to read from the CSV you could use SplFixedArray instead of a plain PHP array. The duplicate check would be the same as above.

PHP 2d Array loop

I have the following.
while($row = mysql_fetch_array($result))
{
$item = "itemCount_".$row['id'];
if ($_POST[$item] > 0)
{
$items2 = array( $i=> array($row['item'],$row['price']));
$i++;
echo $item." = ".$_POST[$item]." ".$i."<br>";
}
}
I would have thought that this would put each item in a array but it only puts the last item in the loop in. where is my fundamental flaw?
$items2 = array( $i=> array($row['item'],$row['price']));
That just keeps reassigning $items2 to a new array. Don't even worry about the $i counter and use
$items2[] = array($row['item'], $row['price']);
PHP Arrays
You're initializing a new array every time you go through the loop, it's better to use the array_push() function.

Categories