3

I've created a import script to convert a spreadsheet containing vehicle makes and models into related database entities. My source array from the spreadsheet looks like this (each is a spreadsheet row):

$rows = [
    ['Brand A', 'Model A'],
    ['Brand A', 'Model A'],
    ['Brand A', 'Model B'],
    ['Brand A', 'Model B'],
    ['Brand A', 'Model B'],
    ['Brand A', 'Model C'],
    ['Brand B', 'Model A'],
    ['Brand B', 'Model B'],
    ['Brand B', 'Model B'],
    ['Brand B', 'Model B'],
    ['Brand B', 'Model C'],
    ['Brand B', 'Model C'],
];

I want this data in this format:

$data = [
    'Brand A' => [
        'Model A',
        'Model A',
        'Model B',
        'Model B',
        'Model B',
        'Model C',
    ],
    'Brand B' => [
        'Model A',
        'Model B',
        'Model B',
        'Model B',
        'Model C',
        'Model C',
    ],
];

I have a working example using a foreach loop:

$data = [];
foreach ($rows as $row) {
    $data[strval($row[0])][] => strval($row[1]);
}

I'd like to use one of the PHP array functions if possible. I've tried the following but it's not creating the brand name indexes:

$data = array_map(function ($row) {
    return $data[strval($row[0])][] = strval($row[1]);
}, $rows);

The array ends up as follows:

$data = [
    'Model A',
    'Model A',
    ...
];

Is this possible or am I wasting my time/over engineering this?


PT 2: Bonus points for making the models unique for a brand at the same time.

$data = [
    'Brand A' => [
        'Model A',
        'Model B',
        'Model C',
    ],
    'Brand B' => [
        'Model A',
        'Model B',
        'Model C',
    ],
];

2 Answers 2

9

one way would be to use array_reduce like this

$data = array_reduce($rows, function ($acc, $row) {
    $acc[$row[0]][] = $row[1];
    return $acc;
}, []);

to make the subarrays unique you can use a combination of array_map and array_unique afterwards

$data = array_map(function ($subarr) {
    return array_unique($subarr);
}, $data);
Sign up to request clarification or add additional context in comments.

2 Comments

+1 because your solution answer the question without a loop as per requested. But I would not use this solution, it is quite too much complicated.Nearly obsfucation here :-)
Nice! Thanks Stephan
0

I honestly think this is over engineering things.

However, I'm going for the bonus point here!

$new = [];
foreach ($rows as $row) {
    $new[$row[0]][] = $row[1];
    $new[$row[0]] = array_unique($new[$row[0]]);
}

8 Comments

Doesn't meet the "no loops" criteria. Nice answer, though.
Yes I know. :-P The guys answer below does, but as you can see it is MORE code and harder to tell what is going on, which is why I wouldn't do it that way unless it was faster over a million iteration benchmark
It does read harder but the problem with loops for me is they end up everywhere in controllers, listeners - even in other loops. So I'll put these iterators into smaller classes and methods, slap some tests on them and they're golden.
You shouldn't have any logic in a controller action. a controllers job is to get data from the request and pass it to a service, get the result, and pass it to a view, and handle any expected exceptions, that's it. Sticking your methods in a separate class is the right thing to do, but make a service class, and call that from the controller so your actions are super tidy and the business logic isn't mixed with framework code
@delboy1978uk exactly. These are going into an import service to be used in a symfony sonata admin class. Debatable, but I think logic in extended vendor classes is worse than in controllers. At least with a controller you are in control (even though it's terrible). If the vendor adds a protected/public method that causes a collision, or just changes something that some of your extended functionality uses you're either stuck at a version or facing a potentially non-trivial refactor.
|

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.