Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

SceL

[Resolvido] in_array problema curioso.

Recommended Posts

Estava eu a desenvolver um sistema para minha empresa, e me deparo com uma fato curioso.

 

Tenho um campo chamado Inicial, Tenho um campo chamado Final.

Dentro de um campo inicial colocamos o valor inicial por exempo 1.

Dentro de um campo final colocamos o valor final por exemplo 2.

O sistema vai cadastrar dentro de um banco de dados todos os valores FLOATs com 2 casas decimais ( 1 1.01 1.02 ... 1.99 2 ) dando um total de 101 números.

 

Mas vem o porém, não é permitido cadastrar números repetidos, por exemplo se previamente cadastrei 1.10 até 1.20 os numeros e seus meios, não deverão ser cadastrados.

 

Imaginei o seguinte:

Farei uma busca no banco com

 

SELECT * FROM `banco` WHERE `valor` >= '" . $_POST['valorInicial'] . "' AND `valorFinal` <= '" . $_POST['valorFinal'] . "'

 

Retorna todos os valores certinhos que eu procurava:

1.10 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.20

Isso eu dando um echo.

 

Joguei todos os valores em uma array previamente criada e "global" para os ifs elses e fors que os utlizarão.

E a cada valor com um while ( $valores = mysql_fetch_array($busca) )

dou um array_push($valores['valor'],$array);

 

Ou seja a array guardará todos os valores anteriormente exibidos com o echo:

1.10 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.20

 

Dou um print_r($array);

Exibe todos sem erro nenhum! Um sucesso.

Até ai tudo bem.

 

Agora na hora de inserir no banco, os valores de 1 até 2 faço da seguinte forma;

for ($i = $_POST['valorInicial']; $i <= $_POST['valorFinal']; $i += 0.01)
{

[indent]if (!in_array($i,$arrays)) mysql_fetch_row("INSERT INTO `banco` VALUES (null,'" . $i . "','" . $_SESSION['idUsuarioLogado'] . "')");[/indent]

}

Todos os valores são realmente inseridos perfeitamente.

 

Então teremos todos os valores de 1 Até 2 Cadastrados ou seja os 101 números.

 

Após eu inserir esses números de 1 até 2, se eu tentar inserir os números de 1 até 2.1 ou seja ele inseria os números de 2.01 até 2.1 ( 2.01 2.02 2.03 ... 2.09 2.1);

Mas pelo meio não sei o que acontece mas o in_array buga e ele adiciona os valores

(1.14 1.36 1.39 1.57 1.59 1.61 1.64 1.66 1.68 1.82 1.84 1.86 1.89 1.91 1.93 2.01 2.02 2.03 2.04 2.05 2.06 2.07 2.08 2.09 2.1)

 

O PHP não pega valores aleatórios, sempre esses.

Não posso por o campo no banco como UNIQUE pois ta assossiado a cada id de Usuário Logado onde podem se repetir numeros.

 

Saidas do sistema:

 

echo $valores['valor'] . " ";

É exibido corretamente (Valores já cadastrados no banco):

1 1.01 1.02 1.03 1.04 1.05 1.06 1.07 1.08 1.09 1.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.2 1.21 1.22 1.23 1.24 1.25 1.26 1.27 1.28 1.29 1.3 1.31 1.32 1.33 1.34 1.35 1.36 1.37 1.38 1.39 1.4 1.41 1.42 1.43 1.44 1.45 1.46 1.47 1.48 1.49 1.5 1.51 1.52 1.53 1.54 1.55 1.56 1.57 1.58 1.59 1.6 1.61 1.62 1.63 1.64 1.65 1.66 1.67 1.68 1.69 1.7 1.71 1.72 1.73 1.74 1.75 1.76 1.77 1.78 1.79 1.8 1.81 1.82 1.83 1.84 1.85 1.86 1.87 1.88 1.89 1.9 1.91 1.92 1.93 1.94 1.95 1.96 1.97 1.98 1.99 2

 

print_r($arrays);

É exibido corretamente (Valores já cadastrados no banco com saida pela array):

Array ( [0] => 1 [1] => 1.01 [2] => 1.02 [3] => 1.03 [4] => 1.04 [5] => 1.05 [6] => 1.06 [7] => 1.07 [8] => 1.08 [9] => 1.09 [10] => 1.1 [11] => 1.11 [12] => 1.12 [13] => 1.13 [14] => 1.14 [15] => 1.15 [16] => 1.16 [17] => 1.17 [18] => 1.18 [19] => 1.19 [20] => 1.2 [21] => 1.21 [22] => 1.22 [23] => 1.23 [24] => 1.24 [25] => 1.25 [26] => 1.26 [27] => 1.27 [28] => 1.28 [29] => 1.29 [30] => 1.3 [31] => 1.31 [32] => 1.32 [33] => 1.33 [34] => 1.34 [35] => 1.35 [36] => 1.36 [37] => 1.37 [38] => 1.38 [39] => 1.39 [40] => 1.4 [41] => 1.41 [42] => 1.42 [43] => 1.43 [44] => 1.44 [45] => 1.45 [46] => 1.46 [47] => 1.47 [48] => 1.48 [49] => 1.49 [50] => 1.5 [51] => 1.51 [52] => 1.52 [53] => 1.53 [54] => 1.54 [55] => 1.55 [56] => 1.56 [57] => 1.57 [58] => 1.58 [59] => 1.59 [60] => 1.6 [61] => 1.61 [62] => 1.62 [63] => 1.63 [64] => 1.64 [65] => 1.65 [66] => 1.66 [67] => 1.67 [68] => 1.68 [69] => 1.69 [70] => 1.7 [71] => 1.71 [72] => 1.72 [73] => 1.73 [74] => 1.74 [75] => 1.75 [76] => 1.76 [77] => 1.77 [78] => 1.78 [79] => 1.79 [80] => 1.8 [81] => 1.81 [82] => 1.82 [83] => 1.83 [84] => 1.84 [85] => 1.85 [86] => 1.86 [87] => 1.87 [88] => 1.88 [89] => 1.89 [90] => 1.9 [91] => 1.91 [92] => 1.92 [93] => 1.93 [94] => 1.94 [95] => 1.95 [96] => 1.96 [97] => 1.97 [98] => 1.98 [99] => 1.99 [100] => 2 )

 

if (!in_array($i,$arrays)) echo $i . " ";

É exibido com erro:

1.14 1.36 1.39 1.57 1.59 1.61 1.64 1.66 1.68 1.82 1.84 1.86 1.89 1.91 1.93 2.01 2.02 2.03 2.04 2.05 2.06 2.07 2.08 2.09 2.1

 

Se alguém ja teve problema parecido com o in_array peço humildemente que me diga como proceder.

 

PS.: com um loop para a array usando comparação $i != $arrays[j], funciona normal, mas creio o loop ser maior, e deixar meu código fonte mais feio.

Mas não tendo jeito voltarei a ele!

Compartilhar este post


Link para o post
Compartilhar em outros sites

É, meu amigo. Parece que encontramos um bug do PHP. Pelo menos não vejo motivos para o seguinte estar ocorrendo:

 

<?php
$inicial = 1.4; //A UNICA ALTERACAO ENTRE OS DOIS SCRIPTS ESTÁ NESSA LINHA
##########################################################################
for ($i = $inicial; $i <= 1.6; $i += 0.01) {
$array[] = $i;
}
$i = 1.55;
echo '<pre>';
print_r($array);
echo (array_search($i, $array)) ? $i : 'N';

 

Resultado:

 

 

Array

(

[0] => 1.4

[1] => 1.41

[2] => 1.42

[3] => 1.43

[4] => 1.44

[5] => 1.45

[6] => 1.46

[7] => 1.47

[8] => 1.48

[9] => 1.49

[10] => 1.5

[11] => 1.51

[12] => 1.52

[13] => 1.53

[14] => 1.54

[15] => 1.55

[16] => 1.56

[17] => 1.57

[18] => 1.58

[19] => 1.59

[20] => 1.6

)

1.55

 

 

Até aí tudo certo. Fez o loop, procurou, encontrou. (usei array_search, mas in_array retornou o mesmo resultado nos dois scripts)

 

<?php
$inicial = 1.3; //A UNICA ALTERACAO ENTRE OS DOIS SCRIPTS ESTÁ NESSA LINHA
##########################################################################
for ($i = $inicial; $i <= 1.6; $i += 0.01) {
$array[] = $i;
}
$i = 1.55;
echo '<pre>';
print_r($array);
echo (array_search($i, $array)) ? $i : 'N';

 

Alterei o inicial para 1.3, aumentando o número de registros, e não encontrou, mesmo estando ali.

 

 

Array

(

[0] => 1.3

[1] => 1.31

[2] => 1.32

[3] => 1.33

[4] => 1.34

[5] => 1.35

[6] => 1.36

[7] => 1.37

[8] => 1.38

[9] => 1.39

[10] => 1.4

[11] => 1.41

[12] => 1.42

[13] => 1.43

[14] => 1.44

[15] => 1.45

[16] => 1.46

[17] => 1.47

[18] => 1.48

[19] => 1.49

[20] => 1.5

[21] => 1.51

[22] => 1.52

[23] => 1.53

[24] => 1.54

[25] => 1.55

[26] => 1.56

[27] => 1.57

[28] => 1.58

[29] => 1.59

)

N

 

 

Fiz diversos testes, e acredito que realmente seja um bug do PHP. Procurei na buglist e encontrei muitos tópicos relacionados (tipagens/in_array/array_search), mas nenhum exatamente sobre isso.

Minha solução foi inutilizar o tipo float/double, convertendo a variável para tipo string. Segue código/resultado:

 

<?php
$inicial = 1.3;
##########################################################################
for ($i = $inicial; $i <= 1.6; $i += 0.01) {
$array[] = (string)$i; //transformei cada valor do array em string
}
$i = 1.55;
echo '<pre>';
print_r($array);
echo (array_search((string)$i, $array)) ? $i : 'N';

 

Resultado:

 

 

Array

(

[0] => 1.3

[1] => 1.31

[2] => 1.32

[3] => 1.33

[4] => 1.34

[5] => 1.35

[6] => 1.36

[7] => 1.37

[8] => 1.38

[9] => 1.39

[10] => 1.4

[11] => 1.41

[12] => 1.42

[13] => 1.43

[14] => 1.44

[15] => 1.45

[16] => 1.46

[17] => 1.47

[18] => 1.48

[19] => 1.49

[20] => 1.5

[21] => 1.51

[22] => 1.52

[23] => 1.53

[24] => 1.54

[25] => 1.55

[26] => 1.56

[27] => 1.57

[28] => 1.58

[29] => 1.59

)

1.55

 

 

Cara, peço desculpas se não era essa sua dúvida. Juro que li três vezes e não entendi com clareza. Daí comecei a criar alguns testes, e me deparei com esse problema, espero que ajude!

 

Um abraço!

Compartilhar este post


Link para o post
Compartilhar em outros sites

realmente tem algum problema aqui

 

começando em 1.3

var_dump( $i, $array[25], $i==$array[25] );

saída:

float(1.55)

float(1.55)

bool(false)

 

e no outro caso, começando em 1.4

 

var_dump( $i, $array[15], $i==$array[15] );

float(1.55)

float(1.55)

bool(true)

Compartilhar este post


Link para o post
Compartilhar em outros sites

É mais ou menos isso que você fez. E sim me pareceu um bug do PHP.

Também me deparei com um bug do MySQL no mesmo sistema mas o contornei.

Se quiserem testar façam o seguinte.

 

Cria um banco de dados e insere valores no banco tipo os que passei ( o campo com esses valores deve ser float ):

1.2 1.21 1.22 1.23 1.24 1.25 1.26 1.27 1.28 etc.

 

tento dotos esses valores por exemplo de 1 até 2.

Teríamos:

1 1.01 1.02 1.03 1.04 ... 1.99 2

 

Faça uma busca no banco por exemplo dos números entre 1.1 e 1.2 o banco vai retornar:

( SELECT * FROM `banco` WHERE `valor` >= 1.1 AND `valor` <= 1.2 )

Resultados obtidos:

1.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.18 1.19 1.2

Está correto.

 

Mas caso você faça a busca por um só valor, por exemplo 1.13 o banco retorna zero registros!

( SELECT * FROM `banco` WHERE `valor` = 1.13 )

Retorno : Zero Registros

 

Para contornar isso substitui os valores float por double e funcionou.

Compartilhar este post


Link para o post
Compartilhar em outros sites

O que funcionou foi a busca no banco de dados, sobre este mesmo problema não funcionouu e ainda fiz um novo post de um problema parecido!

Fiz testes com variáveis maiores ou iguais a 2 não da o mesmo problema.

Se o número por exemplo for inicial de 2.01 e final 3 funciona normal!

Compartilhar este post


Link para o post
Compartilhar em outros sites

O erro não é o in_array e sim o mesmo problema que aconteceu no meu outro tópico que ja foi resolvido.

Alguns valores no float tem resquicios nas casas decimais de valores, por exemplo:

$valor = 1.1;
echo printf("%.20f %.20f\n", intval($valor * 100), ($valor * 100) );

exibirão valores diferentes:

110.00000000000000000000 110.00000000000001421085

 

Para contornar isso fiz assim:

$valor = 1.1;
$esperado = trim( intval(trim($valor * 100 . " ")) . " ");
$recebido = trim( $valor * 100 . " " );

 

É um POG ( Programação Orientada a Gambiarra ) mas esse bug tosco precisa ser contornado de alguma maneira!

Grato aos que tentaram ajudar.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Olá, SceL e Matheus Tavares

a minha opinião é que, não acredito que seja um bug do PHP. Na verdade o laço no for é para contadores inteiros. Assim o incremente deve ser inteiro.

 

Neste mesmo caso acredito que um laço do {...} while(condição); resolve o problema.

 

Veja o exemplo abaixo:

 

$array = array();

$increment = 0.01;

$cont = 1;
$fim = 2;
do{
   $array[] = $cont;
   $cont += $increment;
} while($cont <= $fim);

echo "<pre>"; var_dump($array);

$array2 = array();
$cont = 1;
$fim = 2;
do{
   if(!in_array($cont, $array)){
       $array2[] = $cont;
   }
   $cont += $increment;
} while($cont <= $fim);

echo "<pre>"; var_dump($array2);

 

Imprime:

 

 

array(100) {

[0]=>

int(1)

[1]=>

float(1.01)

[2]=>

float(1.02)

[3]=>

float(1.03)

[4]=>

float(1.04)

[5]=>

float(1.05)

[6]=>

float(1.06)

[7]=>

float(1.07)

[8]=>

float(1.08)

[9]=>

float(1.09)

[10]=>

float(1.1)

[11]=>

float(1.11)

[12]=>

float(1.12)

[13]=>

float(1.13)

[14]=>

float(1.14)

[15]=>

float(1.15)

[16]=>

float(1.16)

[17]=>

float(1.17)

[18]=>

float(1.18)

[19]=>

float(1.19)

[20]=>

float(1.2)

[21]=>

float(1.21)

[22]=>

float(1.22)

[23]=>

float(1.23)

[24]=>

float(1.24)

[25]=>

float(1.25)

[26]=>

float(1.26)

[27]=>

float(1.27)

[28]=>

float(1.28)

[29]=>

float(1.29)

[30]=>

float(1.3)

[31]=>

float(1.31)

[32]=>

float(1.32)

[33]=>

float(1.33)

[34]=>

float(1.34)

[35]=>

float(1.35)

[36]=>

float(1.36)

[37]=>

float(1.37)

[38]=>

float(1.38)

[39]=>

float(1.39)

[40]=>

float(1.4)

[41]=>

float(1.41)

[42]=>

float(1.42)

[43]=>

float(1.43)

[44]=>

float(1.44)

[45]=>

float(1.45)

[46]=>

float(1.46)

[47]=>

float(1.47)

[48]=>

float(1.48)

[49]=>

float(1.49)

[50]=>

float(1.5)

[51]=>

float(1.51)

[52]=>

float(1.52)

[53]=>

float(1.53)

[54]=>

float(1.54)

[55]=>

float(1.55)

[56]=>

float(1.56)

[57]=>

float(1.57)

[58]=>

float(1.58)

[59]=>

float(1.59)

[60]=>

float(1.6)

[61]=>

float(1.61)

[62]=>

float(1.62)

[63]=>

float(1.63)

[64]=>

float(1.64)

[65]=>

float(1.65)

[66]=>

float(1.66)

[67]=>

float(1.67)

[68]=>

float(1.68)

[69]=>

float(1.69)

[70]=>

float(1.7)

[71]=>

float(1.71)

[72]=>

float(1.72)

[73]=>

float(1.73)

[74]=>

float(1.74)

[75]=>

float(1.75)

[76]=>

float(1.76)

[77]=>

float(1.77)

[78]=>

float(1.78)

[79]=>

float(1.79)

[80]=>

float(1.8)

[81]=>

float(1.81)

[82]=>

float(1.82)

[83]=>

float(1.83)

[84]=>

float(1.84)

[85]=>

float(1.85)

[86]=>

float(1.86)

[87]=>

float(1.87)

[88]=>

float(1.88)

[89]=>

float(1.89)

[90]=>

float(1.9)

[91]=>

float(1.91)

[92]=>

float(1.92)

[93]=>

float(1.93)

[94]=>

float(1.94)

[95]=>

float(1.95)

[96]=>

float(1.96)

[97]=>

float(1.97)

[98]=>

float(1.98)

[99]=>

float(1.99)

}

array(0) {

}

 

 

Espero ter ajudado!!!

Compartilhar este post


Link para o post
Compartilhar em outros sites

romabeckman,

agradeço pelas sugestões, mas infelizmente elas não fazem sentido. O for trabalha sim com qualquer condição de loop, e não há nenhuma limitação explícita no manual do PHP nesse sentido. Você não deve ter lido o post do William Bruno, onde sequer fora utilizado loopings. Veja um exemplo com "do { } while;":

 

<?php
$i = 1.3;
do {
$array[] = $i;
$i += 0.01;
} while ($i <= 1.6);
$i = 1.55;
echo '<pre>';
print_r($array);
echo (array_search($i, $array)) ? $i : 'N'; //vai retornar N, pois por algum motivo não encontrou no array.

 

Isso é sim um bug do PHP, e acontece por causa do que foi explicado no post #9 pelo SceL.

 

:thumbsup:

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.