4

I have an array of arrays and I want to copy the first column

The data looks like this:

(0 => "homer",   1 =>  1,   2 =>  2,   3 =>  3)
(0 => "marge",   1 =>  2,   2 =>  4,   3 =>  8)
(0 => "bart",    1 =>  6,   2 =>  2,   3 =>  7)
(0 => "lisa",    1 => 16,   2 => 20,   3 => 71)

Is there a PHP function (similar to array_search) which I can use to search for a name match in the first "column" ?

The data in the first column is already sorted so if I could copy "column1", I could carry out a array_search (which I assume uses a bsearch, rather than a naive element by element iteration).

My questions are:

  • Is there a PHP function similar to array_search, which I can use to search for matching items in the 1st column of the 2D array?

  • Failing that, is there a PHP function to copy the first column into a 1D array (whilst preserving order) so I can call array_search on it ?

Meloman
  • 3,558
  • 3
  • 41
  • 51
oompahloompah
  • 9,087
  • 19
  • 62
  • 90
  • I'm not sure that array_search uses an efficient algorithm, it doesn't seem to care if the input array is ordered. That means it's either a linear search or it sorts the array first anyway. – Matthew Smith Mar 01 '11 at 03:47

5 Answers5

6

Is there a PHP function similar to array_search, which I can use to search for matching items in the 1st column of the 2D array?

You could use array_filter

$matchedArray = array_filter($myArray, function($x) use ($nameToSearchFor) {
    return $x[0] == $nameToSearchFor;
});

Then given:

$myArray = array(
    array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
    array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
    array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
    array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71),
);

$nameToSearchFor = "bart";

Would produce:

 $matchedArray === array(0 => "bart", 1 => 6, 2 => 2, 3 => 7);

I've used closures, that only work in PHP 5.3.0, but you use a traditional callback or create_function in older versions of php

Failing that, is there a PHP function to copy the first column into a 1D array (whilst preserving order) so I can call array_search on it ?

See deceze's first option. I see no need repeating a perfectly good answer.

Community
  • 1
  • 1
xzyfer
  • 13,937
  • 5
  • 35
  • 46
4
$oneDarray = array_map(create_function('$a', 'return $a[0];'), $twoDarray);

Or:

foreach ($twoDarray as $values) {
    if ($values[0] == 'homer') {
        // found!
        break;
    }
}
deceze
  • 510,633
  • 85
  • 743
  • 889
1

This question came top on my Google search for array search column. It took me some time to find this better answer to the same question. By Mark M.

If you are using PHP >= 5.5, then you can use the new array_column(), >in conjunction with array_keys() and array_map().

Applied to this question, to search for "bart", it would be:

$array=array(
    array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
    array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
    array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
    array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71));

$result = $array[array_search("bart",array_column($array, 0))];
print_r($result);

/* Output:
    Array
    (
        [0] => bart
        [1] => 6
        [2] => 2
        [3] => 7
    )
*/

Run demo

Community
  • 1
  • 1
Rasmus
  • 345
  • 2
  • 7
  • This advice is flawed because `array_search()` will return `false` when no match is found. That false will be treated as `0` and will give the first subarray when the result should be no subarray. `maggie` returns `homer`'s row: https://3v4l.org/ZWlQM – mickmackusa Jan 09 '22 at 02:49
0

PHP doesn't have a good clean way of doing this that I know of. However, you can do it yourself using a binary-search since the array is already sorted by the values in the first column of its child arrays. Here is the code to accomplish this:

<?php
// Binary Search Taken By greenmr:
// http://php.net/manual/en/function.array-search.php#89413
function array_bsearch( $needle, $haystack, $comparator ) {
    $high = Count( $haystack ) -1;
    $low = 0;

    while ( $high >= $low ){
        $probe = Floor( ( $high + $low ) / 2 );
        $comparison = $comparator( $haystack[$probe], $needle );
        if ( $comparison < 0 ) {
            $low = $probe +1;
        } elseif ( $comparison > 0 ) {
            $high = $probe -1;
        } else {
            return $probe;
        }
    }

  return -1;
}

// Compare the needle the first element/column 
function KeyCompare( $obj, $needle) {
    if ( $obj[0] < $needle ) {
        return -1;
    } elseif ( $obj[0] > $needle ) {
        return 1;
    } else {
        return 0;
    }
}

$arr = array(array(0=>"homer", 1=> 1, 2=> 2, 3=> 3),
        array(0 => "marge", 1=> 2, 2 => 4, 3=> 8),
        array(0 => "bart", 1 => 6, 2 => 2, 3 => 7),
        array(0 => "lisa", 1 => 16, 2 => 20, 3 => 71));

$index = array_bsearch( 'marge', $arr, 'KeyCompare' );

// prints the array containing marge
echo print_r($arr[$index]);
?>    
troutinator
  • 1,160
  • 1
  • 7
  • 22
0

You could convert the array to use keys using an array_walk

$new_data = array();
array_walk($data, create_function('a','$new_data[$a[0]] = $a;'));
$search_text = 'bart';
if (array_key_exists($new_data, $search_text)) {
    echo "I found '$search_text': ".print_r($new_data[$search_text], true);
}
Matthew Smith
  • 6,165
  • 6
  • 34
  • 35