Estaba haciendo esta pregunta en codewars: "Dada una matriz, encuentra el int que aparece un número impar de veces. Siempre habrá un número entero que aparece un número impar de veces".

Código:

def find_it(seq)
  int = []
  for a in seq do
    count = 0
    for b in seq do
      if a == b
        count += 1
      end
    end
    if count % 2.0 != 0
      int << b
    end
  end      
  puts int.uniq[0].to_i
end

Se probó con un par de entradas, pero las respuestas fueron incorrectas para estas dos matrices:

find_it([1,1,2,-2,5,2,4,4,-1,-2,5]): devuelve 5 en lugar de -1

find_it([1,1,1,1,1,1,10,1,1,1,1]): devuelve 1 en lugar de 10

¿Qué salió mal con mi código?

3
rhea.rao 9 sep. 2018 a las 20:27

4 respuestas

La mejor respuesta
if count % 2.0 != 0
      int << b
    end

El problema que tiene aquí es que empuja b en lugar de a en la matriz de enteros, por lo que lo que sucede es que, en lugar del valor que contó que se empujó, empujó el último valor de b, que es el último elemento de valor en el matriz independientemente de la condición de que el contador sea un número impar, aunque b y el contador no tienen nada que ver entre sí. para solucionarlo, reemplaza b con a para que empuje el valor que está probando en comparación con los otros elementos en el segundo bucle

Reparar:

if count % 2.0 != 0
      int << a
    end

Un código similar pero más simple que hace un trabajo similar, excepto de una manera más corta y más comprensible es:

def find_it(seq)
  numberWithOddCount = 0
  seq.each do |currentElement|
    counter = 0
    seq.each { |elementToCompare| counter += 1 if currentElement == elementToCompare}
    numberWithOddCount = currentElement if counter % 2 != 0
  end
  numberWithOddCount
end

Acabo de agregar algunos bits tid que también podría utilizar para acortar y simplificar el código.

¡Feliz codificación!

Nota :

Puede utilizar los métodos integrados de ruby de maneras creativas para hacer que el código haga lo que quiera en muy pocas líneas (o incluso una línea) como lo que hizo @iGian en los comentarios de las preguntas, pero si todavía es nuevo en ruby, entonces es mejor utiliza esos métodos uno por uno cuando los aprendas, de lo contrario te confundirás. Pero si está dispuesto a tomarse el tiempo para aprenderlos, le sugiero que tome su código y separe la ejecución de cada método en su propia línea y muestre lo que cada método había hecho para saber qué está haciendo qué. y practica usar cada uno por separado.

1
aimen alt 10 sep. 2018 a las 01:27
def find_it(seq)
  seq.group_by{|x| x}.select{|k, v| (v.count % 2.0 !=0)}.first[0]
end

El código anterior tomará una secuencia en una matriz. Aquí estamos agrupando por elementos:

Por ejemplo:

[1,1,2,-2,5,2,4,4,-1,-2,5].group_by{|x| x}
# => {1=>[1, 1], 2=>[2, 2], -2=>[-2, -2], 5=>[5, 5], 4=>[4, 4], -1=>[-1]}

Después de obtener los resultados anteriores, estamos encontrando los elementos cuyos elementos no cuentan con la condición de selección.

Por ejemplo:

[1,1,2,-2,5,2,4,4,-1,-2,5].group_by{|x| x}.select{|k, v| (v.count % 2.0 !=0)}

Obtendremos los resultados como {-1=>[-1]}

Nosotras estamos tomando la clave como elemento de resultado.

1
Holger Just 10 sep. 2018 a las 20:15

Gracias por todas las respuestas detalladas, estoy revisando las respuestas de todos ahora. Soy nuevo en Ruby y todavía estoy en el proceso de aprender los métodos / reglas para usarlos / la notación Big O, por lo que aprecio mucho el aporte de todos. Codewar enumeró algunas de las soluciones mejor clasificadas. Este parece ser el más rápido hasta ahora:

def find_it(seq)   
   seq.detect { |n| seq.count(n).odd? } 
end
0
rhea.rao 10 sep. 2018 a las 19:27

@aimen_alt tiene razón acerca de su error

Pero descompongamos tu problema.

Primero, necesitas calcular las apariencias de cada número. En segundo lugar, debes encontrar el que tenga el recuento impar de las apariencias. De acuerdo con el problema, solo hay uno de esos números, por lo que puede devolverlo de inmediato.

Puede seguir su camino y hacerlo en complejidad O(N^2) escaneando su secuencia para cada elemento de la secuencia (por lo tanto, N elementos en la secuencia se multiplican por el tamaño de la secuencia N = { {X3}}). Puede hacerlo linealmente * construyendo un Hash y luego podrá obtener la clave con un valor impar:

def find_it(seq)
  numbers = {}
  seq.each do |item|
    numbers[item] = numbers[item].to_i + 1
  end
  numbers.select{ |k,v| v.odd? }.first.first
end

Para ser más idiomático, puede usar group_by para agrupar los números:

seq = [1, 2, 6, 1, 2]
seq.group_by{ |item| item }
#=> {1=>[1, 1], 2=>[2, 2], 6=>[6]}

Puede ver que cada valor es una matriz, y solo necesita obtener uno con la cantidad impar de elementos:

seq = [1, 2, 6, 1, 2]
seq.group_by{ |item| item }.select{ |k, v| v.size.odd? }
#=> {6=>[6]}

Y lo último que le gustaría hacer es obtener el valor de la clave:

seq.group_by{ |item| item }.select{ |k, v| v.size.odd? }.keys.first

Entonces, la solución final sería

def find_it(seq)
  seq.group_by{ |item| item }
     .select{ |k, v| v.size.odd? }
     .keys
     .first
end

Como @pascalbetz mencionó:

def find_it(seq)
  seq.group_by{ |item| item }
     .find{ |k, v| v.size.odd? }
     .first
end
1
fl00r 10 sep. 2018 a las 13:49