Pergunta

É possível usar array_map () para valores de teste de um array? Eu quero ter certeza de que todos os elementos de um array são numéricos.

Eu tentei tanto

$arrays = array(
         array(0,1,2,3 )
        , array ( 0,1, "a", 5 )
);

foreach ( $arrays as $arr ) {

        if ( array_map("is_numeric", $arr) === FALSE ) {
                echo "FALSE\n";
        } else {
                echo "TRUE\n";
        }
}

e

$arrays = array(
         array(0,1,2,3 )
        , array ( 0,1, "a", 5 )
);

foreach ( $arrays as $arr ) {

        if ( ( array_map("is_numeric", $arr) ) === FALSE ) {
                echo "FALSE\n";
        } else {
                echo "TRUE\n";
        }
}

E para tanto eu recebo

TRUE
TRUE

Isso pode ser feito? Se assim for, o que estou fazendo de errado?

Nota:. Estou ciente de que posso obter o meu funcionalidade desejada a partir de um loop foreach

Foi útil?

Solução

array_map retorna um array. Por isso vai ser sempre considerada 'verdadeira'. Agora, se você array_search para FALSE, você pode ser capaz de obter os efeitos desejo.

A partir da PHP.net Página

array_map() returns an array containing all the elements of 
arr1 after applying the callback function to each one.

Isto significa que atualmente você tem uma matriz que contém verdadeiras ou falsas para cada elemento. Você precisaria usar array_search(false,$array) para descobrir se existem falsos valores.

Outras dicas

Eu geralmente sou um grande defensor de array_map(), array_filter(), etc., mas, neste caso foreach() vai ser a melhor escolha. A razão é que, com array_map() e outros, ele vai passar por toda a matriz não importa o que. Mas para os seus propósitos você só precisa ir através da matriz até que seja executado em um valor para o qual is_numeric() retorna falso, e, tanto quanto eu sei não há nenhuma maneira em PHP para romper com esses métodos.

Em outras palavras, se você tem 1.000 itens no seu conjunto eo 5º não é numérico, usando array_map() irá ainda verificar os 995 valores restantes, mesmo que você já conhece a matriz não passar o teste. Mas se você usar um foreach () em vez e tê-lo break em is_numeric() == false, então você só precisa verificar os primeiros cinco elementos.

Você pode usar o filtro, mas acaba com um pouco horrível de código

$isAllNumeric = count(array_filter($arr, "is_numeric")) === count($arr)

Usando uma função personalizada torna um pouco melhor, mas ainda não perfeito

$isAllNumeric = count(array_filter($arr, function($x){return !is_numeric($x);})) === 0

Mas se você estivesse usando funções personalizadas array_reduce iria funcionar, mas ainda tem algumas falhas.

$isAllNumeric = array_reduce($arr,
                             function($x, $y){ return $x && is_numeric($y); },
                             true);

As falhas são de que ele não vai quebrar quando ele encontrou o que quer, então as sugestões funcionais acima não são muito eficientes. Você precisa escrever uma função como esta:

function array_find(array $array, $callback){
    foreach ($array as $x){ //using iteration as PHP fails at recursion
        if ( call_user_func($callback, array($x)) ){
            return $x;
        }
    }
    return false;
}

E usá-lo como assim

$isAllNumeric = array_find($arr, function($x){return !is_numeric($x);})) !== false;

i tem dois pequenos, mas extremamente úteis funções no meu "biblioteca padrão"

function any($ary, $func) {
   foreach($ary as $val)
      if(call_user_func($func, $val)) return true;
   return false;
}

function all($ary, $func) {
   foreach($ary as $val)
      if(!call_user_func($func, $val)) return false;
   return true;
}

no seu exemplo

 foreach ( $arrays as $arr )
    echo all($arr, 'is_numeric') ? "ok" : "not ok";

A mais elegante abordagem IMHO :

foreach ($arrays as $array)
{
 if (array_product(array_map('is_numeric', $array)) == true)
 {
  echo "TRUE\n";
 }

 else
 {
  echo "FALSE\n";
 }
}

Isto irá retornar true se todos os valores são numéricos e falso se qualquer um dos valores não é numérico.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top