0

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:

  1. Each line has 3 fields.
  2. 3rd field becomes a key in a new associative array.
  3. Two remaining fields (1st and 2nd) become values for that key.
  4. 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.

1
  • Did you give up??? Commented May 14, 2019 at 20:28

5 Answers 5

1

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);
}
Sign up to request clarification or add additional context in comments.

1 Comment

Yes...exactly what I was looking for - and extremely fast...Thanks! I was overthinking about my problem:) Also, compared to other answers, this one is the shortest and the simplest.
0

More memory efficient would be:

  1. Not reading the whole file in memory. fgetcsv reads one line at a time
  2. 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);

Comments

0

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.

Comments

0

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
                )

        )

Comments

0

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 :)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.