3

I'm trying to retrieve the object which has the lowest distance value from an array of objects. This is my data set below;

[0] => myObjectThing Object
    (
        [name:myObjectThing:private] => asadasd
        [distance:myObjectThinge:private] => 0.9826368952306
    )

[1] => myObjectThing Object
    (
        [name:myObjectThing:private] => 214gerwert24
        [distance:myObjectThinge:private] => 1.5212312547306
    )

[2] => myObjectThing Object
    (
        [name:myObjectThing:private] => abc123
        [distance:myObjectThinge:private] => 0.0000368952306
    )

So I'd like to be able to retieve the object which has the smallest distance value. In this case it would be object with name: abc123

** EDIT ** What would happen if I only used arrays, e.g.

array(
      array('name' => 'bla', 'distance' => '123');
      array('name' => 'b123a', 'distance' => '1234214');
);

Would this be easier to find the min value?

2
  • "What would happen if I only used arrays?" - you could then array_multisort (au2.php.net/manual/en/function.array-multisort.php). But it wouldn't make a bug difference in this case because you can just use array_walk Commented Mar 2, 2011 at 11:18
  • Typically the fringe clarification that is asked is: What is the preferred output if two of the objects have the same minimal distance value? The answers below are only returning the first encountered min. On other pages on Stack Overflow, an array of results is populated. Commented Apr 19, 2023 at 21:13

7 Answers 7

11

Hmm for PHP >= 5.3 I would try something like this:

$Object = array_reduce($data,function($A,$B){
    return $A->distance < $B->distance ? $A : $B;
})

For PHP < 5.3 the fillowing would suffice:

function user_defined_reduce($A,$B){
    return $A->distance < $B->distance ? $A : $B;
}
$Object = array_reduce($data,"user_defined_reduce");
Sign up to request clarification or add additional context in comments.

Comments

7

Previously suggested answers did not explain the need to include an $initial value to array_reduce(). The solution did not work because of it.

This one works for me (PHP 5.3.13):

$array = array(
    array(
        'name' => 'something',
        'value' => 56
    ),
    array(
        'name' => 'else',
        'value' => 54
    ),
    array(
        'name' => 'else',
        'value' => 58
    ),
    array(
        'name' => 'else',
        'value' => 78
    )
);
$object = array_reduce($array, function($a, $b){
    return $a['value'] < $b['value'] ? $a : $b;
}, array_shift($array));

print_r($object);

This will give me:

[0] => Array
(
    [name] => else
    [value] => 54
)

Whereas the previous solution gave me null. I'm assuming that PHP < 5.3 would require a similar initial value to be specified to array_reduce().

1 Comment

If you're looking for a minimum value with array_reduce in unsorted array, I think there's a chance you won't get the minimum value?
0

You can't flatten this as it isn't a plain old multi-dimensional array with just the values.

This should work:

$min = $object[0];
for ($i = 1; $i < count($object); $i++)
    if ($object[$i]['distance'] < $min['distance'])
        $min = $object[$i];

4 Comments

And which object has the minimal value ? You didn't got it - just minimal value.
If I didn't use objects and just had a massive array would this be easier? Only problem with doing it with a big array is that it's a bit hacky. My only problem with using another loop is that I am already at O(n^2) which will be huge if i wrap another loop in there
Would it be possible to integrate it into your main loop to avoid pushing past O(n)? Or is your main loop not through the objects?
It's through another data set, so i'm pulling data then for each element im then making another request for that data. If i added another loop within this i think it would be too cumbersome
0

This example should give you a hint in the right direction:

<?php

$a = new stdClass();
$a->foo = 2;
$b = new stdClass();
$b->foo = 3;
$c = new stdClass();
$c->foo = 1;

$init = new stdClass();
$init->foo = 1000;

$vals = array( $a, $b, $c );

var_dump(
    array_reduce(
        $vals,
        function ( $x, $y )
        {
            if ( $x->foo < $y->foo )
            {
                return $x;
            }   
            else
            {
                return $y;
            }   
        },  
        $init
    )   
);  

?>

Comments

0

try:

$myObjectCollection = ...;
$minObject = $myObjectCollection[0]; // or reset($myObjectCollection) if you can't ensure  numeric 0 index

array_walk($myObjectCollection, function($object) use ($minObject) { 
        $minObject = $object->distance < $minObject->distance ? $object : $minObject;
});

but from the looks of your dump. name and distance are private. So you want be able to access them from the object directly using ->. You'll need some kind of getter getDistance()

Comments

0
$objectsArray = array(...); // your objects
$distance     = null;
$matchedObj   = null;

foreach ( $objectsArray as $obj ) {
   if ( is_null($distance) || ( $obj->distance < $distance ) ) {
      $distance   = $obj->distance;
      $matchedObj = $obj;
   }
}

var_dump($matchedObj);

AD EDIT:

If you will use arrays instead of objects, change $obj->distance to $obj['distance'].

Comments

-1

I stumbled on this question while I was searching for a way to find the lowest value instead of the entire object. In case somebody else is looking for the same thing, here's my approach:

$min_value = min( array_map( fn($o) => $o->my_prop, $objects ) );

1 Comment

Differently from other answers, this concise snippet will iterate over the array twice instead of only once. This answer does not return the "minimal object", it returns the minimal my_prop value.

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.