Skip to content
Advertisement

PHP array merging, ignore certain duplicated keys and let them be included in the inner created arrays

I’m merging together arrays with the same set inner array name, changing the key value to the order number then creating further inner arrays for items that are not duplicated with this code…

function readCSV($csvFile)
    {
        $line_of_text = [];
        $file_handle = fopen($csvFile, 'r');
        //skip csv headers
        //fgetcsv($file_handle);
        //fgetcsv($file_handle);
        fgetcsv($file_handle);  
        while (!feof($file_handle)) {
            $tmp = fgetcsv($file_handle, 1024);

            if (isset($line_of_text[$tmp[0]])) {
                foreach ($tmp as $k => $v) {

                    if (array_key_exists($k, $line_of_text[$tmp[0]])) {
                        if (!is_array($line_of_text[$tmp[0]][$k])) {
                            $kVal = $line_of_text[$tmp[0]][$k];

                            $line_of_text[$tmp[0]][$k] = [];
                            $line_of_text[$tmp[0]][$k][] = $kVal;
                        }

                        $line_of_text[$tmp[0]][$k][] = $v;
                        $line_of_text[$tmp[0]][$k] = array_unique($line_of_text[$tmp[0]][$k]);
                        $line_of_text[$tmp[0]][$k] = array_filter($line_of_text[$tmp[0]][$k]);

                        if (count($line_of_text[$tmp[0]][$k]) == 1) {
                            $line_of_text[$tmp[0]][$k] = array_values($line_of_text[$tmp[0]][$k]);
                            $line_of_text[$tmp[0]][$k] = $line_of_text[$tmp[0]][$k][0];
                        }

                        if (empty($line_of_text[$tmp[0]][$k])) {
                            $line_of_text[$tmp[0]][$k] = null;
                        }

                    } else {
                        $line_of_text[$tmp[0]][$k] = null;
                    }
                }
                $line_of_text[$tmp[0]][0] = $tmp[0];

            } else {
                $line_of_text[$tmp[0]] = $tmp;
            }

        }

        fclose($file_handle);
        return array_filter(array_values($line_of_text));
    }

    // Set path to CSV file
    $csvFile = 'my.csv';
    $csv = readCSV($csvFile);

//$csv is your array
foreach($csv as $key => $value){
 if(!array_key_exists(@$value[0],$arr)){
  $arr[@$value[0]] = [];
  }
  $arr[@$value[0]] = array_merge($arr[@$value[0]],$value);  
}
echo "<pre>";
print_r($arr);
echo '</pre>'; 

This turns..

Array
(
    [0] => Array
        (
            [0] => 15304
            [1] => item1
            [2] => qty = 1
        )

    [1] => Array
        (
            [0] => 15304
            [1] => item2
            [2] => qty = 1
        )

    [2] => Array
        (
            [0] => 15305
            [1] => itemX
            [2] => qty = 2
        )
}

into

Array
(
    [15304] => Array
        (
            [0] => 15304
            [1] => Array
                (
                [0]item1
                [1]item2
                )
            [2] => qty = 1
        )

    [15305] => Array
        (
            [0] => 15305
            [1] => itemX
            [2] => qty = 2
        )
}

So because qty = 1 is the same its getting filtered out, when what I need is..

Array
(
    [15304] => Array
        (
            [0] => 15304
            [1] => Array
                (
                [0]item1
                [1]item2
                )
            [2] => Array
                (
                [0]qty = 1
                [1]qty = 1
                )
        )

    [15305] => Array
        (
            [0] => 15305
            [1] => itemX
            [2] => qty = 2
        )
}

How can I exclude certain ones from the “remove duplicates” part so they are repeated in an inner-array as in my last example? This is needed as they are directly linked to other items with an inner array, so if for example the item1 inner array now has 6 items the qty now needs to also have all 6 items in the inner array, even if they are the same.

Advertisement

Answer

Your current code is good for two cases:

  1. Reading all data as is, without modification
  2. Reading all data and performing a universal modification

Since what you need is a conditional modification, it seems like you would be better off creating the structure of the array manually. Doing so would add another benefit: code clarity. You should always strive for descriptive code, so building your array with descriptive associative keys would make the intent of the code clearer.

Proposed solution based off the example data (rough sketch that you should tailor to your specific needs):

function readCSV($csvFile)
{
    $output = [];
    $fileHandle = fopen($csvFile, 'r');
    $header = fgetcsv($fileHandle);
    while (!feof($fileHandle)) {
        $fileRow = fgetcsv($fileHandle, 1024);
        $orderId = $fileRow[0];
        // skip this row if it's empty (the first field contains no id)
        if (empty($orderId)) {
            continue;
        }
        /*
          $fileRow[3] is "Buyer name", the first field that's present in one type of row
          (the one containing common properties of the order). By checking if it's empty,
          we identify the contents of the row - not empty means order row with common
          properties, empty means item row with specific item properties.
         */
        if (!empty($fileRow[3])) {
            // no need to repeat the id inside the array - it's already stored in the key
            $output[$orderId] = [
                'order_number' => $fileRow[1],
                'buyer_username' => $fileRow[2],
                'buyer_name' => $fileRow[3],
                // here you can continue explicitly adding any property you need
            ];
        } else {
            // add a new item entry
            $output[$orderId]['items'][] = [
                'item_number' => $fileRow[20],
                'item_title' => $fileRow[21],
                'quantity' => $fileRow[24],
                'price' => $fileRow[25],
                // here you can continue explicitly adding any property you need
            ];
        }
    }
    fclose($fileHandle);

    return $output;
}

Now all the items of your order are neatly stored as subarrays, each containing only data specific to that item, which makes it really easy to iterate:

foreach($orders[$orderId]['items'] as $item)
User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement