2

I have this multidimensional array $currencies:

$currencies = array ( 
    0 => (object) array( 'name' => 'algo', 'fullName' => 'Algorand'), 
    1 => (object) array( 'name' => 'ardr', 'fullName' => 'Ardor'), 
    2 => (object) array( 'name' => 'eth', 'fullName' => 'Eth')
);

And I want to keep only the objects with a name that is in this array:

$filter = ["eth", "algo"];

I did this, but it doesn't work.

$currenciesFiltered = array_filter(
    $currencies,
    function ($value) use ($filter) {
        return in_array($value['name'], $filter);
    }
);

Where is my mistake?

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
djoo
  • 685
  • 1
  • 7
  • 24
  • I don't see any mistakes. Please show your array $currencies in PHP notation (as output var_export ($ currencies)). – jspit Jun 08 '20 at 12:33
  • 1
    Why it doesn't work? Is any error thrown? Maybe it's because you used an object of type `stdClass` as array? `return in_array($value->name, $filter)` – Mihai Matei Jun 08 '20 at 12:36
  • 1
    @jspit i did it. Maybe it's because of the (object) ? What do you think about this ? – djoo Jun 08 '20 at 13:43
  • 1
    Easy enough to take away the `(object)` casting and see if it works... – JakeParis Jun 08 '20 at 13:44
  • @MihaiMatei sounds good what you said. I this this error : Symfony\Component\ErrorHandler\Error\FatalError Method Illuminate\View\View::__toString() must not throw an exception, caught Facade\Ignition\Exceptions\ViewException: Cannot use object of type stdClass as array – djoo Jun 08 '20 at 13:44
  • 1
    It works with `$value->name`, with the code you have shown us. If it doesn’t work with what you have - then something must be significantly different, from what you have shown. – CBroe Jun 08 '20 at 13:50
  • Same task, different data-type: [Keep array rows where a column value is found in a second flat array](https://stackoverflow.com/q/47503473/2943403) – mickmackusa Mar 30 '23 at 22:09

2 Answers2

2

According to the error output:

Uncaught Error: Cannot use object of type stdClass as array in [...][...]:13

You are casting the array to an object, but then trying to use it as an array later. When you remove the (object) casting, it works just as you are expecting.

If you must cast to an object, do it after the filter.

JakeParis
  • 11,056
  • 3
  • 42
  • 65
  • Thanks Jake, i didn't find out the first time there is an object inside. It's when i saw the replies of jspit and Minhai Matei So i did this just before doing the filter foreach($currencies as $key => $currency){ $currencies[$key] = (array) $currency; } – djoo Jun 08 '20 at 13:52
  • More simple : Use : $value->name, $filter); – djoo Jun 08 '20 at 13:56
1

PHP already has native, optimized functions to compare/filter data from two iterable datasets.

array_uintersect(), in this case is perfect for filtering based on value.

Because the source array(s) that populate the $a and $b variable during iteration cannot be predicted, each attempt to access data must fallback to the alternate array's data.

Because only the $currencies array contains rows of objects, check for a name property inside the callback. If the property does not exist, you know that the accessible value belongs to the flat $filter array.

Code: (Demo)

var_export(
    array_uintersect(
        $currencies,
        $filter,
        fn($a, $b) =>
            ($a->name ?? $a)
            <=>
            ($b->name ?? $b)
    )
);

The above has the same effect as making iterated in_array() calls inside of array_filter(). Demo

var_export(
    array_filter(
        $currencies,
        fn($obj) => in_array($obj->name, $filter)
    )
);

Both techniques output:

array (
  0 => 
  (object) array(
     'name' => 'algo',
     'fullName' => 'Algorand',
  ),
  2 => 
  (object) array(
     'name' => 'eth',
     'fullName' => 'Eth',
  ),
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136