views:

116

answers:

5

I have an array like this

$data = array(
    "163",
    "630",
    "43",
    "924",
    "4",
    "54"
);

How can I select the smallest and largest values from it according to string length NOT number value. (for this example it is 1 (smallest) and 3 (largest).

+2  A: 
$min = 100;
$max = -1;

foreach($data as $a){
  $length = strlen($a);
  if($length > $max){ $max = $length; }
  else if($length < $min){ $min = $length; }
}
brian_d
it does exactly what the op wants.
Femaref
thank you fernaref
brian_d
that's right though. `$min` has to start at a very high number (int32.maxvalue perhaps?)
Femaref
true. have made edit
brian_d
Or you can set $max/$min to the first element and (optionally) skip it in the iteration. (Easier to do that with a `for` loop.)
konforce
@konforce: With that approach you'd have to make sure you are accessing valid entries (think of arrays with 0 or 1 elements), and will introduce more checks.
NullUserException
Either way you have to check for an empty array. With Brian's code, you get `$min=100, $max = -1` on an empty array. So assuming you now have a non-empty array, there is no additional condition with `for ($i = 1; $i < $len; ++$i)`. And in fact, you avoid the if/else on the first iteration (since it's skipped). Plus, `foreach` tends to be the worst performing way to iterate in PHP. But these are minor points, and I digress...
konforce
+3  A: 

Here's an improved version of brian_d's code:

$min = PHP_INT_MAX;
$max = -1;

foreach ($data as $a) {
    $length = strlen($a);
    $max = max($max, $length);
    $min = min($min, $length);
}
NullUserException
This seems overly complex (with the addition of an initialized `$min` and `$max`), unless you are dealing with a huge array that you only want to traverse once.
Peter Ajtai
+1  A: 

Although in this case it is not advisable because you'll be traversing the array twice, you can also use array_reduce to compare each element against the rest. Like this:

<?php

$data = array('163','630','43','42','999','31');
//Will return the longest element that is nearest to the end of the array (999)
//That's why we use strlen() on the result.
$max_l = strlen(array_reduce($data,'maxlen'));
//Will return the shortest element that is nearest to the end of the array (31)
$min_l = strlen(array_reduce($data,'minlen'));

echo "The longest word is $max_l characters, while the shortest is $min_l\n";

function maxlen($k,$v) {
        if (strlen($k) > strlen($v)) return $k;
        return $v;
}
function minlen($k,$v) {
        if ($k == '') return PHP_INT_MAX;
        if (strlen($k) < strlen($v)) return $k;
        return $v;
}
?>

If you are using PHP 5.3.0+ you can take advantage of closures:

<?php
   $max_l = strlen(array_reduce($data,
                function ($k,$v) { return (strlen($k) > strlen($v)) ? $k : $v; }
        ));

   $min_l = strlen(array_reduce($data,
                function ($k,$v) {
                        if (!$k) return PHP_INT_MAX;
                        return (strlen($k) < strlen($v)) ? $k : $v;
                }
        ));

echo "The longest word is $max_l characters, while the shortest is $min_l\n";
?>
Vinko Vrsalovic
A: 
<?php
$array = array(
    "163",
    "630",
    "43",
    "924",
    "4",
    "54"
);
$arraycopy  = array_map('strlen',$array);
asort($arraycopy);

$min = reset($arraycopy);

//if you need a single 'minword'
$minword = $array[key($arraycopy)];
//if you need them all
$minwords = array_intersect_key($array,array_flip(array_keys($arraycopy,$min)));


$max = end($arraycopy);
//if you need a single 'maxword'
$maxword = $array[key($arraycopy)];
//if you need them all:
$maxwords = array_intersect_key($array,array_flip(array_keys($arraycopy,$max)));

var_dump($min,$max,$minword,$maxword,$minwords,$maxwords);
Wrikken
+3  A: 

Seems like you should use an array_map()

  // Convert array to an array of string lengths
$lengths = array_map('strlen', $data);

  // Show min and max string length
echo "The shortest is " . min($lengths) .
     ". The longest is " . max($lengths);

Live example

Note that the $lengths array is unsorted, so you can easily retrieve the corresponding number for each string length.

Peter Ajtai
+1 Neat. You could just do `array_map('strlen', $data)` though;
NullUserException
@NullUser - WOW! I don't know why, but I thought that didn't work >:(
Peter Ajtai
The *only* reason I didn't accept this on is becuase it uses 5.3.0, otherwise really neat!
Mark
@Mark - Well, now it doesn't... I don't know why, but for some bizarre reason, I thought you couldn't use native functions with an array map.... *FACE PALM*
Peter Ajtai
This is by far the cleanest solution, but it's not very efficient, as it traverses the array three times (array_map, min and max), so if you have huge arrays, better use a single loop.
Vinko Vrsalovic
@Vinko - Yeah, I guess that's where NullUserException's answer would gain the advantage (in the case of a huge array... or using this function very very many times on many many arrays).
Peter Ajtai