php foreach loop giving only 1 result from the array - php

I have a csv file containing attributes of the stores (id, name, category, featured, etc) to be displayed in a project. For now I need to display an array of featured stores with the condition 'featured'='TRUE'. There are 10 results.
Here's the code to read the file and save the data as an associative array
function read_all_stores() {
$file_name = 'csv_files/stores.csv';
$fp = fopen($file_name, 'r');
$first = fgetcsv($fp); // get the first row aka headlines of the file
$stores = [];
while ($row = fgetcsv($fp)) {
$i = 0;
$store = [];
foreach ($first as $col_name) {
$store[$col_name] = $row[$i];
$i++;
}
$stores[] = $store;
}
return $stores;
}
sample result of the first 5 stores
Now I want to display only the stores that has attribute featured = 'TRUE'. I tried this code:
function get_store() {
$stores = read_all_stores();
$feature = [];
foreach ($stores as $s) {
while ($s['featured'] == 'TRUE') {
$feature[] = $s;
return $feature;
}
}
return false;
}
But it only returns one result.
I tried removing the single quotation mark but it seems to only accept the 'TRUE' value as string instead of boolean. How can I fix this foreach loop??

Your problem is that as soon as you find a matching result: $s['featured'] == 'TRUE', you return it: return $feature;. Instead, you need to process all values in $stores before returning your result. If there are matching stores (count($feature) is non-zero i.e. truthy), return them, otherwise return false.
function get_store() {
$stores = read_all_stores();
$feature = [];
foreach ($stores as $s) {
if ($s['featured'] == 'TRUE') {
$feature[] = $s;
}
}
return count($feature) ? $feature : false;
}

Two problems in your code:
In get_store() method you are returning as soon as you find a match. Instead you should add all the matched ones and then return at the end.
For checking a match you should use if instead of while
Here is the modified version of your code:
<?php
function read_all_stores() {
$file_name = 'stores.csv';
$fp = fopen($file_name, 'r');
$first = fgetcsv($fp); // get the first row aka headlines of the file
$stores = [];
while ($row = fgetcsv($fp)) {
$i = 0;
$store = [];
foreach ($first as $col_name) {
$store[$col_name] = $row[$i];
$i++;
}
$stores[] = $store;
}
return $stores;
}
function get_store() {
$stores = read_all_stores();
$feature = [];
foreach ($stores as $s) {
if ($s['featured'] == 'TRUE') {
$feature[] = $s;
}
}
return $feature;
}
echo count(get_store());

Related

Retrieving data from CSV in PHP

I have a CSV file containing two rows of data, one which the user will input and the other will be returned. e.g. inputting a post/zipcode which will be found in the CSV file, the data in the next cell should be returned.
<?php
function csv_to_array($filename='bn.csv', $delimiter=',')
{
if(!file_exists($filename) || !is_readable($filename))
return FALSE;
$header = NULL;
$data = array();
if (($handle = fopen($filename, 'r')) !== FALSE)
{
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
{
if(!$header)
$header = $row;
else
$data[] = array_combine($header, $row);
}
fclose($handle);
}
return $data;
}
function search($data, $x) {
for($i = 0; $i < sizeof($data); $i++) {
if($data[$i] == $x) return $i;
}
return -1;
}
$data = array("bn.csv");
echo search($data, "BN1 1AA");
print_r(csv_to_array('bn.csv'));
?>
Currently I am just getting -1 returned, what should I do?
Thanks in advance.
$data = array("bn.csv"); creates an array with the literal string bv.csv in it. I'm guessing you want $data = csv_to_array("bn.csv"); here instead. I would build an associative array like this:
$data = [
'BN1 1AA' => 'E05002432',
'...' => '...',
'...' => '...',
];
Via something like:
while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE) {
$data[$row[0]] = $row[1];
}
Thus, you can refer to an entry directly by its key, you don't need to iterate over every item to search for a match:
$search = 'BN1 1AA';
if (array_key_exists($search, $data)) {
echo $data[$search];
} else {
echo "not found";
}
There are several problems towards the end of your code.
In search() - you are trying to match the postcode with the entire row in $data[$i] == $x, $data[$i] is actually a list of the fields in the row, so perhaps matching it with ($data[$i][$field] == $x) and $field is the field name of the postcode.
You were calling search() with an array of the file names for the data and not the data from the file, so this code calls csv_to_array() first and passes the result to search()...
Lastly - the sample data didn't have BN1 1AA in it anyway, so should return -1.
function search($data, $x, $field = 'Postcode') {
for($i = 0; $i < sizeof($data); $i++) {
if ($data[$i][$field] == $x)
return $i;
}
return -1;
}
$data = csv_to_array('a.csv');
print_r($data);
echo search($data, "BN1 1AD");

why am i only getting the first row value in array "row" in the below code. i need all the values corresponding to the query

$s = $conn->prepare($q);
$s->execute([$tagIdValue]);
$d = $s->fetchAll();
return $d;
function x($d) {
foreach ($d as $row) {
$val = $row["id"];
$cont = trimContent($row);
return $row;
}
}
i have a query , which returns all the values in the table and a function to convert it into an assosiate array. But only getting the first row in the array
Because ur using return inside loop, it only take first value and return it.
$s = $conn->prepare($q);
$s->execute([$tagIdValue]);
$d = $s->fetchAll();
return $d;
function x($d) {
$arr =[]
foreach ($d as $row) {
$val = $row["id"];
$cont = trimContent($row);
array_push($arr, $val)
}
return $arr;
}
Because, you are returning the result set in the loop.
So, only the first row is returned from the loop.
As, in the first iteration, return statement is encountered, so, that function will return and control will get out of the function.
And next iterations will not loop over the result set.
We need to create an array before loop,
append results to that array
and return the array.
Corrected Code:
$s = $conn->prepare($q);
$s->execute([$tagIdValue]);
$d = $s->fetchAll();
return $d;
function x($d) {
$array = array();
foreach ($d as $row) {
$val = $row["id"];
$cont = trimContent($row);
$array[] = $row;
}
return $array;
}
Instead writing a return inside a loop, replace that line with an array push or array shift function.
Once the loop has ended return the final result obtained from array_push/array_shift.
Put your return outside the loop so only it returns only the first loop
function x($d) {
foreach ($d as $row) {
$val = $row["id"];
$cont = trimContent($row);
return $row;
}
}
You need to return outside the loop :
$s = $conn->prepare($q);
$s->execute([$tagIdValue]);
$d = $s->fetchAll();
return $d;
function x($d) {
$arr =array();
foreach ($d as $k=> $row) {
$val = $row["id"];
$cont = trimContent($row);
$arr[$k] = $row;
}
return $arr;
}

$array[$key] = $something creates a new array

I have this php code that's supposed to check how many times a single item is in an array and put the amount in the value of that key.
im asking, why does the $duplicates[$item] += 1; create a new array instead of appending it to the existing array
here is the picture of the output I get.
this is my code:
$itemQuery = $con->prepare("SELECT cart_value FROM active_carts WHERE username=:prodName");
$itemQuery->bindParam(":prodName" , $uname , PDO::PARAM_STR);
$itemQuery->execute();
$itemCount = $itemQuery->fetchAll();
$arrax = $itemCount[0]["cart_value"];
$itemArrX = explode(",", $arrax);
$inQuestion = array();
$duplicates = array();
foreach ($itemArrX as $item) {
if (in_array($item , $inQuestion)) {
$counter = 0;
if (!array_key_exists($item , $duplicates)) {
$duplicates[$item] = $counter;
// doesnt even execute
} else {
echo $duplicates[$item]; // echoes a new array every time
$duplicates[$item] += 1;
}
} else {
array_push($inQuestion, $item);
}
}
It is rather simple, you never created that item in the array.
$data[$key] = $value; //examine that.
try this $duplicates[$item] = $item;
then $duplicates[$item] += 1;
If you're just looking for a count of duplicate values, I like the suggestion about array_count_values() in the comments. That can be run through array_filter() to remove the non-duplicate values.
$itemQuery = $con->prepare("SELECT cart_value FROM active_carts WHERE username=:prodName");
$itemQuery->execute([":prodName"=>$uname]);
$itemArrX = explode(",", $itemQuery->fetchColumn(0));
$itemArrX = ["foo","bar","baz","bar","boo","baz"];
$duplicates = array_filter(array_count_values($itemArrX), function($v){return $v>1;});
$inQuestion = array_unique($itemArrX);
print_r($duplicates);
print_r($inQuestion);
Or here's a condensed version of your code which should work just fine.
$itemQuery = $con->prepare("SELECT cart_value FROM active_carts WHERE username=:prodName");
$itemQuery->execute([":prodName"=>$uname]);
$itemArrX = explode(",", $itemQuery->fetchColumn(0));
$itemArrX = ["foo","bar","baz","bar","boo","baz"];
$duplicates = [];
$inQuestion = [];
foreach ($itemArrX as $item) {
if (in_array($item, $inQuestion)) {
echo $duplicates[$item];
$duplicates[$item]++;
} else {
$duplicates[$item] = 1;
$inQuestion[] = $item;
}
}
print_r($duplicates);
print_r($inQuestion);

Compare 2 csv files with php and return changed row numbers

I've script that compares 2 csv files and put changed row id's into array:
//Function for comparing two files
function row_compare($a, $b)
{
if ($a === $b)
{
return 0;
}
return (implode("",$a) < implode("",$b) ) ? -1 : 1;
}
//Set previous csv file
$file1 = new SplFileObject("file1.csv");
$file1->setFlags(SplFileObject::READ_CSV);
//Set new csv file
$file2 = new SplFileObject("file2.csv");
$file2->setFlags(SplFileObject::READ_CSV);
foreach ($file1 as $row)
{
$csv_1[] = $row;
}
foreach ($file2 as $row)
{
$csv_2[] = $row;
}
//Check differences
$all_unique_rows = array_udiff($csv_1, $csv_2, 'row_compare');
//Get rows id which have difference
foreach($all_unique_rows as $key=>$unique_row)
{
foreach($unique_row as $element)
{
$rowwwithdiffer[] = array($key);
}
}
It works fine! But what I want to achieve - instead of getting 1, 2, 3 - use 1 - 3, it is - if changed rows are consecutive, use intervals instead of each changed row id...
how I can achieve it? ;-)
TNX!
You will have to run trough the array with the id's and check if they are consecutive and them deal with them accordingly.
$aglutinatedRows = [];
$lastRowId = $rowwwithdiffer[0];
$firstRowInSequence = $rowwwithdiffer[0];
foreach(array_slice($rowwwithdiffer, 1) as $row) {
if ($row == $lastRowId + 1) {
$lastRowId = $row;
} else {
$aglutinatedRows[] = $firstRowInSequence != $lastRowId ? $firstRowInSequence . ' - ' . $lastRowId : lastRowId;
$firstRowInSequence = $row;
$lastRowId = $row;
}
}

PHP Array only stores last value

Well, basically what this code does is grab some links from a source code of a website and send them to an mp3 player.
The big problem is on the get_link function, where i want to store the urls to an array. The section where im having problems is commented.
Sorry for posting all this code but the functions are connected to each others.
function getHost($db,$id){
if(isset($_GET['id'])){
$sql1 = "SELECT host FROM mixtape WHERE id=?";
$stm = $db->prepare($sql1);
$stm->execute(array($id));
$row1 = $stm->fetch(PDO::FETCH_ASSOC);
if($row1['host']=='host1'){
$sql2 = "SELECT link1 FROM faixa WHERE id_mixtape IN(SELECT id FROM mixtape WHERE id=?)";
$stm = $db->prepare($sql2);
$stm->execute(array($id));
$rows_affected = $stm->rowCount();
$array=array();
if (count($rows_affected) > 0) {
for($i=1; $i <= $rows_affected; $i++) {
$row2 = $stm->fetch(PDO::FETCH_ASSOC);
$url=$row2['link1'];
get_Link($db,$url,$i,$rows_affected,$array);
}
}
}
}
}
function get_Link($db,$url,$pos,$rows_affect,$array){
$find = 'url:';
$reg_exUrl = "/(http|https|ftp|ftps)\:\/\/[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(\/\S*)?/";
$data = file_get_contents($url);
$data = explode("\n", $data);
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[]=$link;
}
}
if($pos!=$rows_affect-1){
$url="mylink.com/".$link."|";
}else{
$url="mylink.com/".$link."&amp";
}
$array[$pos]=$url;
var_dump($array); // Here says that are 3 values in the array. True
if($pos==$rows_affect-1){
var_dump($array); // Here is only showing the last value in the array. Why?
player($db,$array);
}
}
function player($db,$array){
if(isset($_GET['id'])){
foreach($array as $i=>$item){
echo $item;
}
}
}
This piece of code:
$c=0;
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[$c]=$link;
}
}
Should be like:
$c=0;
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[$c]=$link;
$c = $c+1; //this is missing or $c++;
}
}
OR:
for ($line = 0; $line < count($data); $line++) {
if (strpos($data[$line], $find) !== false) {
$link = preg_replace($reg_exUrl,"", $data[$line]);
$v[]=$link; //That way works too
}
}
Miguelfsf, you must first learn about variable scope.
Your problem is, you created the $array=array() (the $array show be the $row2).
You declared a new variable, but you didn't used, the $array was just to tell you, declare your array that way
$row2=array().
After that you need to do
$row2[] = $stm->fetch(PDO::FETCH_ASSOC);
Why?
Because the assoc returns a associative array, then it will do
$array => {title => "last title} = $newData => {title => "new title"}
It will replace the value
Using the [] everytime you do this it'll create a new element.
Then
{
0 => { title => "title1"}
1 => { title => "title2"}
2 => { title => "title3"}
3 => { title => "title4"}
}

Categories