Create an array within an array using a string from key - php

I can't get past making what I think is a 2D Array in PHP. I'm using a CSV as source input and want to take one of the columns and split that into an array as well.
$csv = array_map("str_getcsv", file("data/data.csv", FILE_SKIP_EMPTY_LINES));
$keys = array_shift($csv);
foreach ($csv as $i => $row) {
$csv[$i] = array_combine($keys, $row);
$linkto = $csv[$i]['linkto'];
// $linktoArray = explode(" ", $linkto);
echo '<pre>';
// print_r($linktoArray);
echo '</pre>';
$csv[$i] = array_combine($keys, $row);
}
$csv['timestamp'] = time();
echo '<pre>';
print_r($csv);
echo '</pre>';
Will output:
Array
(
[0] => Array
(
[color] => 1
[shape] => 0
[label] => string
[size] => 1
[linkto] => 1 2 3
)...
Using something similar to what I commented out, I'd love to see something like:
Array
(
[0] => Array
(
[color] => 1
[shape] => 0
[label] => string
[size] => 1
[linkto] => Array
(
[0]=>1
[1]=>2
[2]=>3
)
)...
However, right now I'm just getting an array before my containing array. Pardon my ignorance, I haven't had much experience past the front-end. Any suggestions? I'm sure this has been explained before, but I can't find the right terminology to utilize a search.

It's fairly straight forward. All you need to do is this:
$linkto = $csv[$i]['linkto'];
$linktoArray = explode(" ", $linkto);
$csv[$i]['linkto'] = $linktoArray;
After having read through your code again, you seem to be struggling with the concept of foreach. When you use foreach you don't access $csv[$i] like you have, you just use $row. Try something like:
//The & symbol means any changes made to $row inside the foreach will apply outside the foreach.
foreach($csv as $i => &$row) {
$row['linkto'] = explode(" ", $row['linkto']);
}
That should be all you need, none of this array_combine stuff.

Here is a modified example from the SplFileObject::fgetcsv documentation that might simplify your code enough to isolate what might be giving you issues:
$file = new SplFileObject("data/data.csv");
$file->setFlags(SplFileObject::READ_CSV | SplFileObject::SKIP_EMPTY);
$header_row = ($file->fgetcsv());
foreach ($file as $row) {
$row = array_combine($header_row, $row);
$row['linkto'] = explode(" ", $row['linkto']);
$csv[] = $row;
}
print_r($csv);

Related

How to access elements of array in php

Below is the code snippet:
$resultArray = explode("\n",$cmd);
print_r($resultArray);
$tempArray = array();
foreach($resultArray as $key){
$tempArray = explode(" ",$key);
print_r($tempArray);
}
first print gives output:-
Array
(
[0] => AA-BB-E3-1B-81-6A 10.10.10.2
[1] => CC-DD-E3-1B-7E-5A 10.10.10.3
)
Second print gives output:-
Array
(
[0] => AA-BB-E3-1B-81-6A
[1] => 10.10.10.2
)
Array
(
[0] => CC-DD-E3-1B-7E-5A
[1] => 10.10.10.3
)
Array
(
[0] =>
)
Assuming there will be many entries of mac addresses corresponding mac addresses, I want to store them in separate variables for further use.
Please help. I am new to PHP, learning on my own. Any help is appreciated.
eidt 1: Expected output should be two arrays, one each for mac address and Ip Address from which I would be able to loop through and query database for each mac address.
Well I'm not sure what you want to do, but from the little I understood is to separate the mac addresses:
$resultArray = explode("\n", $cmd);
print_r($resultArray);
$tempArray = array();
foreach($resultArray as $key){
$dm = explode(" ", $key);
$tempArray[] = $dm[0];
}
print_r($tempArray);
The result would be:
Array
(
[0] => AA-BB-E3-1B-81-6A
[1] => CC-DD-E3-1B-7E-5A
.
.
.
)
It would be much better if you put the expected result, in order to help you better.
You forget [] for tempArray :
$resultArray = explode("\n",$cmd);
print_r($resultArray);
$tempArray = array();
foreach($resultArray as $key){
$tempArray[] = explode(" ",$key);
print_r($tempArray);
}

Creating an associative array from one-dimension array

Was not really sure on what question's title should be here...
Sample .csv:
tennis,soccer,sports
car,plane,things
jeans,shirt,things
My final, ideal, outcome should be an array that looks like this:
Array
(
[sports] => Array
(
[0] => tennis
[1] => soccer
)
[things] => Array
(
[0] => car
[1] => plane
[2] => jeans
[3] => shirt
)
)
Here is my most recent attempt to achieve the outcome above (after many tries):
<?php
$f_name = 'test.csv';
// Stores all csv data
$csv_data = array_map('str_getcsv', file($f_name));
$c = count($csv_data);
$tmp = array();
$data_for_email = array();
for ($i = 0; $i < $c; $i++) {
// Remove last element and make it a key
$le = array_pop($csv_data[$i]);
$tmp[$le] = $csv_data[$i];
$data_for_email = array_merge_recursive($data_for_email, $tmp); // MEMORY ERROR
}
print_r($data_for_email);
?>
This is what I get as a result:
Array
(
[sports] => Array
(
[0] => tennis
[1] => soccer
[2] => tennis
[3] => soccer
[4] => tennis
[5] => soccer
)
[things] => Array
(
[0] => car
[1] => plane
[2] => jeans
[3] => shirt
)
)
As you can see, I get duplicates of .csv's line 1 in [sports] array.
More detailed description of my requirement:
Each line has 3 fields.
3rd field becomes a key in a new associative array.
Two remaining fields (1st and 2nd) become values for that key.
Because multiple lines may (and do) contain identical 3rd field (while combination of 1st and 2nd fields are always different), I need to then merge all these duplicate keys' values into 1.
P.S. I could parse that array (to remove duplicate values) afterwards, but the real .csv file is large and it becomes too slow to process it, and I receive the following error at the line which I marked with // MEMORY ERROR:
Fatal Error: Allowed Memory Size of 134217728 Bytes Exhausted
I tried increasing the memory limit but I'd prefer to avoid this if possible.
Should be a little easier. No need for array_merge_recursive:
foreach($csv_data as $row) {
$key = array_pop($row);
if(!isset($data_for_email[$key])) {
$data_for_email[$key] = [];
}
$data_for_email[$key] = array_merge($data_for_email[$key], $row);
}
More memory efficient would be:
Not reading the whole file in memory. fgetcsv reads one line at a time
Avoiding a recursive merge
Code:
$handle = fopen($f_name, 'r');
if (!$handle) {
// Your error-handling
die("Couldn't open file");
}
$data_for_email = array();
while($csvLine = fgetcsv($handle)) {
// Remove last element and make it a key
$le = array_pop($csvLine);
if (isset($data_for_email[$le])) {
$data_for_email[$le] = array_merge($data_for_email[$le], $csvLine);
} else {
$data_for_email[$le] = $csvLine;
}
}
fclose($handle);
You just need to initialize $tmp in every loop which will resolve your problem. Check below code:
for ($i = 0; $i < $c; $i++) {
// Remove last element and make it a key
$le = array_pop($csv_data[$i]);
$tmp = []; //Reset here
$tmp[$le] = $csv_data[$i];
$data_for_email = array_merge_recursive($data_for_email, $tmp); // MEMORY ERROR
}
Hope it helps you.
Use the name for the key to get a unique list. It is cheaper than merge if there is a lot of data.:
$handle = fopen('test.csv', 'r');
$res = [];
while ($data = fgetcsv($handle)) {
list($first, $second, $type) = $data;
$res[$type] = ($res[$type] ?? []);
array_map(function($e)use(&$res, $type) {
$res[$type][$e] = $e;
}, [$first, $second]);
}
output:
Array
(
[sports] => Array
(
[tennis] => tennis
[soccer] => soccer
)
[things] => Array
(
[car] => car
[plane] => plane
[jeans] => jeans
[shirt] => shirt
)
)
i made something, too, but now the others were faster. :D
I've made it oop, it doesn't quite come out what you wanted but maybe it helps you further.
I have not come any further now, unfortunately, wanted to show it to you anyway :)
Here is your index.php ( or whatever the file is called. )
<?php
include "Data.php";
$f_name = 'in.csv';
// Stores all csv data
$csv_data = array_map('str_getcsv', file($f_name));
$c = count($csv_data);
$tmp = array();
$data_for_email = array();
foreach ($csv_data as $data){
$key = array_pop($data);
array_push($data_for_email,new Data($data,$key));
}
foreach ($data_for_email as $data){
array_push($tmp,$data->getValue());
}
foreach ($tmp as $value){
print_r($value);
echo "<br>";
}
and here the class Data:
<?php
class Data
{
private $value = [];
public function __construct($data, $key)
{
$this->value[$key]=$data;
}
/**
* #return array
*/
public function getValue()
{
return $this->value;
}
}
as output you bekome something like that:
Array ( [sports] => Array ( [0] => tennis [1] => soccer ) )
Array ( [things] => Array ( [0] => car [1] => plane ) )
Array ( [things] => Array ( [0] => jeans [1] => shirt ) )
ps:
surely there is another function that summarizes the same keys, but somehow i don't find anything now...
I hope it helps :)

how to check multiple items are in an array or not with PHP

I'm reading an RTF file that gets uploaded by the user, I then exploded this file on each \pard to get each line and then preg_split each line into an array. I then loop over the array looking for a certain value and get the data next to it. All this is working fine but what's the best way to do this multiple times looking for multiple strings? Here is what I have so far:
$data = explode('\pard',$rtf);
foreach ($data as $item) {
$values = preg_split('/[\t]/', $item);
if (in_array('shipped yesterday', $values)){
$key = array_search('shipped yesterday', $values);
print $values[$key + 1];
}else{
print_r($values);
}
}
The RTF file looks like the following:
booked in yesterday 50 41 78
packaged yesterday 62 45 48
shipped yesterday 46 52 62
So my code above is looking for 'shipped yesterday' then getting the first value next to it, in this case 46.
What's the most efficient way to do it for the rest of the values 'booked in yesterday' and 'packaged yesterday'?
I think the fastest way would be a simple regex.
preg_match_all('/((?:booked in|packaged|shipped) yesterday)\s+(\d+)/i',$rtf,$matches);
$values = array();
foreach($matches[1] as $key => $match){
$values[$match] = $matches[2][$key];
}
print_r($values);
This will parse all matching the given pattern into an array as such
Array (
['booked in yesterday'] => '50'
['packaged yesterday'] => '62'
['shipped yesterday'] => '46'
)
Note if you need the numeric value just parse before passing into the array
$values[$match] = intval($matches[2][$key]);
The output from matches would be like this just to clarify the building of the array:
Array (
[0] => Array (
[0] => 'booked in yesterday 50'
[1] => 'packaged yesterday 62'
[2] => 'shipped yesterday 46'
)
[1] => Array (
[0] => 'booked in yesterday'
[1] => 'packaged yesterday'
[2] => 'shipped yesterday'
)
[2] => Array (
[0] => '50'
[1] => '62'
[2] => '46'
)
)
Your code looks fine to me, you could take an excerpt and use it as a function. HOWEVER, as you asked about efficiency, it's worth noting that isset is faster than in_array
For example...
function checkForValue($searchterm, $values) {
if (isset($values[$searchterm]))
return $values[$searchterm];
}else{
return "$searchterm not found";
}
}
$data = explode('\pard',$rtf);
foreach ($data as $item) {
$values = preg_split('/[\t]/', $item);
print checkForValue('shipped yesterday', $values);
print checkForValue('packaged yesterday', $values);
}
Maybe you could try running another foreach within an array of the required test strings ?
Have a look at this :-
<?php
$checkString = array("shipped yesterday","booked in yesterday","packaged yesterday");
$data = explode('\pard',$rtf);
foreach ($data as $item)
{
$values = preg_split('/[\t]/', $item);
foreach($checkString as $check)
{
if (in_array($check, $values))
{
$key = array_search($check, $values);
print $values[$key + 1];
}
else
{
print_r($values);
}
}
}
?>

PHP Array Inconsistency?

I have some code that pushes values into a PHP array via array_push(). However, when I do print_r() on the array, it skips a key, and the ending result looks like this:
Array (
[0] => appease
[1] => cunning
[2] => derisive
[3] => effeminate
[4] => grievance
[5] => inadvertently miscreants
[7] => ominous
[8] => resilient
[9] => resolute
[10] => restrain
[11] => superfluous
[12] => trudged
[13] => undiminished
)
As you can see, it skipped the 6th value, and moved onto the next one. For some reason though, if I call the foreach() method on the array, it stops after "grievance", or index 4. Does anyone know why it does this?
Edit: if I do echo $words[6], it prints the value of the 6th index correctly.
Edit 2: here's my code:
$return = file_get_contents($target_file);
$arr = explode('<U><B>', $return);
$a = 1;
$words = [];
foreach($arr as $pos) {
$important = substr($arr[$a], 0, 20);
$arr2 = explode("</B></U>",$important);
array_push($words,strtolower(trim($arr2[0])));
$a++;
}
Contents of the file are:
<U><B>appease</B></U><U><B>cunning</B></U><U><B>derisive</B></U><U><B>effeminate</B></U><U><B>grievance</B></U><U><B>inadvertently</B></U><U><B>miscreants</B></U><U><B>ominous</B></U><U><B>resilient</B></U><U><B>resolute</B></U><U><B>restrain</B></U><U><B>superfluous</B></U><U><B>trudged</B></U><U><B>undiminished</B></U>
*removed some irrelevant file content for easier readability
i wrote something simplier:
<?php
$return="<U><B>appease</B></U><U><B>cunning</B></U><U><B>derisive</B></U><U><B>effeminate</B></U><U><B>grievance</B></U><U><B>inadvertently</B></U><U><B>miscreants</B></U><U><B>ominous</B></U><U><B>resilient</B></U><U><B>resolute</B></U><U><B>restrain</B></U><U><B>superfluous</B></U><U><B>trudged</B></U><U><B>undiminished</B></U>";
$arr = explode('<U><B>', $return);
$words = [];
foreach($arr as $pos) {
if(!empty($pos)){
$words[]=strip_tags($pos);
}
}
echo '<pre>';
print_r($words);
demo: http://codepad.viper-7.com/XeUWui
$arr = "<U><B>appease</B></U><U><B>cunning</B></U><U><B>derisive</B></U><U><B>effeminate</B></U><U><B>grievance</B></U><U><B>inadvertently</B></U><U><B>miscreants</B></U><U><B>ominous</B></U><U><B>resilient</B></U><U><B>resolute</B></U><U><B>restrain</B></U><U><B>superfluous</B></U><U><B>trudged</B></U><U><B>undiminished</B></U>";
$arr = explode('<U><B>', $arr);
$a = 1;
foreach($arr as &$pos)
{
if(!empty($pos))
{
$pos = str_replace("</B></U>","",$pos);
}
}
print_r(array_filter($arr));
Might be overkill but there is always SimpleXml as well:
$arr = "<U><B>appease</B></U><U><B>cunning</B></U><U><B>derisive</B></U><U><B>effeminate</B></U><U><B>grievance</B></U><U><B>inadvertently</B></U><U><B>miscreants</B></U><U><B>ominous</B></U><U><B>resilient</B></U><U><B>resolute</B></U><U><B>restrain</B></U><U><B>superfluous</B></U><U><B>trudged</B></U><U><B>undiminished</B></U>";
$xml = new SimpleXmlElement('<root>' . $arr . '</root>');
$words = $xml->xpath('//B');
foreach ($words as $i =>$word) {
printf("%d.\t%s\n", $i+1, $word);
}
This is pretty simple with regex:
<?php
$words = "<U><B>appease</B></U><U><B>cunning</B></U><U><B>derisive</B></U><U><B>effeminate</B></U><U><B>grievance</B></U><U><B>inadvertently</B></U><U><B>miscreants</B></U><U><B>ominous</B></U><U><B>resilient</B></U><U><B>resolute</B></U><U><B>restrain</B></U><U><B>superfluous</B></U><U><B>trudged</B></U><U><B>undiminished</B></U>";
preg_match_all("#<U><B>(.*?)</B></U>#",$words,$matches);
print_r($matches[1]);
?>
Fiddle here

magento array_merge

This array_merge doesn't seem to work for me. I am trying merge all the arrays in one array like this:
foreach ($collection as $result) {
$i++;
if(empty($json)){
$json = $result->getData();
}else{
$json = array_merge($json, $result->getData());
}
}
print_r($json);
I have 3 arrays in the collection. But when I do print_r($json); it only shows me the last array like this.
Array (
[po_id] => 3
[title] => Test3
[geo_address] => M1 2FF
[latitude] => 53.449137
[longitude] => -2.364551
[display_address] => testing
[url] => http://testing.com
[phone] => 0321654987
[status] => 1
[type] => 1
[created_time] => 2012-01-26 11:07:05
[update_time] => 2012-01-26 11:10:13
[distance] => 3708.40724665926
)
I am expecting this to merge all three arrays and print that out.
I'm kinda expecting it like this:
Array (
[po_id] => 1
[title] => Test1
[geo_address] => M1 2FF
[po_id] => 2
[title] => Test2
[geo_address] => M2 2FF
[po_id] => 3
[title] => Test3
[geo_address] => M3 2FF
)
Means all the arrays should be merged in on array.
EDITTED
I have it working. In fact this what I was looking for:
$json = array();
foreach ($collection as $key=>$result) {
$data = $result->getData();
$json[$key]['postorefinder_id'] = $data['postorefinder_id'];
$json[$key]['title'] = $data['title'];
$json[$key]['geo_address'] = $data['geo_address'];
$json[$key]['latitude'] = $data['latitude'];
$json[$key]['latitude'] = $data['latitude'];
$json[$key]['longitude'] = $data['longitude'];
$json[$key]['display_address'] = $data['display_address'];
$json[$key]['url'] = $data['url'];
$json[$key]['phone'] = $data['phone'];
$json[$key]['status'] = $data['status'];
$json[$key]['type'] = $data['type'];
$json[$key]['created_time'] = $data['created_time'];
$json[$key]['update_time'] = $data['update_time'];
$json[$key]['distance'] = $data['distance'];
}
return json_encode($json);
Thanks #cillosis, your example really helped.
According to the array_merge() function on php.net:
If the input arrays have the same string keys, then the later value for that key will overwrite the previous one. If, however, the arrays contain numeric keys, the later value will not overwrite the original value, but will be appended.
This means, every time you try to merge them, because they are using the same key, it just gets overwritten. That's why you only see the last array.
[EDIT]
So how would I concatenate multiple arrays with the same keys in one array?
I don't see how two elements can share the same key unless that key contained another array like this:
foreach ($collection as $result) {
// Get collection of data
$data = $result->getData();
// Assign each result to multi-dimensional array
$json['po_id'][] = $data['po_id'];
$json['title'][] = $data['title'];
$json['geo_address'][] = $data['geo_address'];
$json['latitude'][] = $data['latitude'];
// ... the rest of them go here ...
}
That is untested, just threw it together real quick. It should output something like:
Array(
"po_id": Array(
"first_po_id",
"second_po_id",
"third_po_id"
),
"title": Array(
"first_title",
"second_title",
"third_title"
)
)
With more data than that of course.
Unfortunately the structure you're hoping for is not possible in PHP. Have a read about the array type; if you try to assign a value to a pre-existing key, it overwrites any existing value:
$array = array('foo' => 'bar');
$array = array_merge($array, array('foo' => 'new'));
var_dump($array['foo']); // new
Depending on how you want to manipulate the resulting data, you can use array_merge_recursive:
$json = array();
foreach ($collection as $result) {
$json = array_merge_recursive($json, $result->getData());
}
or alternatively you might want the collections to group by result:
// make $json a copy of $collection
$json = $collection;
// overwrite $result within $json
foreach ($json as &$result) {
$result = $result->getData();
}
EDIT: See example output for each of these approaches.

Categories