Search code examples
phplaravelcollectionsilluminate

Why does flattening a collection of collections yield into an array of all the arrays values?


Using laravel, I create a collection of collection of array items.

I expect to work on each array item during the map by first flattening the collection of collections.

Yet instead of getting each array item, I suddenly iterate over each array's value (the key ist lost in the process). Why? What is going on here?

    public function testItFlattensCollectionOfCollections()
    {
        $json = <<<JSON
[
  [
    {
      "userId": "10",
      "foo": "bar"
    },
    {
      "userId": "11",
      "foo": "baz"
    }

  ],
  [
    {
      "userId": "42",
      "foo": "barbaz"
    }
  ]
]
JSON;

        $content = json_decode($json, true);

        $collection = collect($content)
            ->map(fn ($items) => collect($items))
            ->flatten();

        $actual = $collection->toArray();
        $this->assertSame(
            [
                [
                    'userId' => '10',
                    'foo' => 'bar',
                ],
                [
                    'userId' => '11',
                    'foo' => 'baz',
                ],
                [
                    'userId' => '42',
                    'foo' => 'barbaz',
                ],
            ],
            $actual
        );
        
        $this->assertNotSame(['10', 'bar', '11', 'baz', '42', 'barbaz'], $actual);
    }

Solution

  •         $collection = collect($content)
                ->map(fn ($items) => collect($items))
                ->flatten(depth: 1)
    

    If you take a look at the collection's flatten method, you will see it offers an optional parameter $depth and it defaults to infinity.

    It therefore tries to flat it down as far as possible, which in your case basically means it flattens twice, both your collection of collections and also all the arrays within each collection.