0

I come from a Javascript background, and I am trying to use array_filter(), but it works quite different from JS.

Taking this JS example:

const people = [
  {
    name: 'Will',
    username: 'will',
  },
  {
    name: 'Alex',
    username: 'alex',
  },
  {
    name: 'Abraham',
    username: 'abraham',
  },
];

const usernameToFind = 'abraham';

const found = people.filter(person => person.username === usernameToFind);

console.log(found[0]); // index 0

// {
//   name: 'Abraham',
//   username: 'abraham'
// }

I expect all the usernames to be different, so it is always going to return only one value. So if I want to access the information found I just ask for index 0.

On PHP:

<?php

$people = [
  [
    'name' => 'Alex',
    'username' => 'alex',
  ],
  [
    'name' => 'Will',
    'username' => 'will',
  ],
  [
    'name' => 'Abraham',
    'username' => 'abraham',
  ],
];

$usernameToFind = 'abraham';

$found = array_filter($people, function($person) use ($usernameToFind) {
  return $person['username'] === $usernameToFind;
});

print_r($found);

// Array
// (
//     [2] => Array
//         (
//             [name] => Abraham
//             [username] => abraham
//         )
// )

So my issue is: I get an array with the index of the element found, but I don't know what the index is.

I saw this question but it is quite different: PHP array_filter to get only one value from an array.

I am not using array_search(), because my needle to search is 2 or 3 levels deep like:

array_filter($people, function ($person) use ($cityToFind) {
   return $person['location']['city'] === $cityToFind;
}

I can use a for loop, but I really wanted to use filter instead. Thanks in advance!

Abraham
  • 8,525
  • 5
  • 47
  • 53
  • We don't have a [mcve] here. Stack Overflow does have pages dedicated to setting up an array_search call on a multidimensional array, but it will not have a lower time complexity than a conditionally broken foreach loop. – mickmackusa Aug 12 '22 at 11:43

2 Answers2

3

You can do a couple things.

  1. To get the first element of the array you can use reset($found) https://www.php.net/manual/en/function.reset.php

  2. After filtering the array you can reset the array keys to start at 0 using array_values($found) https://www.php.net/manual/en/function.array-values.php

Dan
  • 10,614
  • 5
  • 24
  • 35
2

Using array_filter() will always process the entire array, in your example it's the last entry so it needs to anyway. But if you had 500 entries and it was the first 1, it will still check all 500 entries.

Instead you could use a simple foreach() loop which stops as soon as it finds the first one...

foreach ( $people as $index => $person )    {
    if ( $person['username'] === $usernameToFind )  {
        echo "Index={$index} name={$person['name']}";
        break;
    }
}

gives...

Index=2 name=Abraham

As an answer to your original question - you can use After array_filter(), how can I reset the keys to go in numerical order starting at 0 to reset the keys so you can use [0].

Nigel Ren
  • 56,122
  • 11
  • 43
  • 55
  • I would not use a foreach instead of an array_filter for performance readons : you calculate complexity based on the worst case, not on "if this instance of the problem is easier". Moreover, you'd have to get a really long array (in the hundred thousand items) to need actual performance requirements. – smwhr Jul 10 '20 at 20:06
  • 1
    @smwhr, I don't calculate complexity on theory, more on practical application. `array_filter()` is not about finding 1 entry in an array - it can select multiple items from the array, different use case. – Nigel Ren Jul 10 '20 at 20:10
  • I know, it's a pain that there's no `uarray_search` method in PHP (let's imagine one that could infer a binary search and improve practical and theorical complexity on a well ordered array). That said, I also have a feud with the foreach/break pattern because it causes a lot of trouble when debugging an error. – smwhr Jul 10 '20 at 20:20
  • I very much support Nigel's explanation as to why a conditionally broken foreach is always the better design plan versus array_filter for the task of finding a single entry. – mickmackusa Aug 12 '22 at 11:40