¿Si hay dos elementos máximos de una matriz?
En este código, si el usuario escribe 2, dos veces y 1, dos veces. Luego hay dos elementos máximos y tanto Kinder como Twix deben imprimirse. Pero cómo ? Probablemente pueda hacer esto con el método if, pero esto hará que mi código sea aún más largo. ¿Alguna versión genial? ¿Puedo hacer esto con solo uno si?
a = [0, 0, 0,]
b = ["Kinder", "Twix", "Mars"]
while true
input = gets.chomp.to_i
if input == 1
a[0] += 1
elsif input == 2
a[1] += 1
elsif input == 3
a[2] += 1
elsif input == 0
break
end
end
index = a.index(a.max)
chocolate = b[index] if index
print a.max,chocolate
Respuestas
La pregunta realmente no tiene nada que ver con cómo ase construye la matriz .
def select_all_max(a, b)
mx = a.max
b.values_at(*a.each_index.select { |i| a[i] == mx })
end
b = ["Kinder", "Twix", "Mars"]
p select_all_max [0, 2, 1], b
["Twix"]
p select_all_max [2, 2, 1], b
["Kinder", "Twix"]
Consulte Array # values_at .
Alternativamente, esto podría hacerse en una sola pasada.
def select_all_max(a, b)
b.values_at(
*(1..a.size-1).each_with_object([0]) do |i,arr|
case a[i] <=> arr.last
when 0
arr << i
when 1
arr = [i]
end
end
)
end
p select_all_max [0, 2, 1], b
["Twix"]
p select_all_max [2, 2, 1], b
["Kinder", "Twix"]
p select_all_max [1, 1, 1], b
["Kinder", "Twix", "Mars"]
Una forma sería la siguiente:
Primero, simplemente separe la recopilación de entrada del conteo, por lo que solo recopilaremos la entrada en este paso:
inputs = []
loop do
input = gets.chomp.to_i
break if input.zero?
inputs << input
end
Ahora podemos contar las entradas. Si tiene Ruby 2.7, simplemente puede hacerlo counts_by_input = inputs.tallypara obtener { "Twix" => 2, "Kinder" => 2 }. De lo contrario, mi enfoque preferido es usar group_by con transform_values :
counts_by_input = inputs.group_by(&:itself).transform_values(&:count)
# => { "Twix" => 2, "Kinder" => 2 }
Ahora, dado que vamos a extraer valores basados en su recuento, queremos tener los recuentos como claves. Normalmente, podríamos invertir el hash, pero eso no funcionará en este caso porque solo nos dará un valor por clave, y necesitamos múltiples:
inputs_by_count = counts_by_input.invert
# => { 2 => "Kinder" }
# This doesn't work, it removed one of the values
En su lugar, podemos usar otro group_by y transform_values(la razón por la que me gustan estos métodos es porque son muy versátiles ...):
inputs_by_count = counts_by_input.
group_by { |input, count| count }.
transform_values { |keyvals| keyvals.map(&:first) }
# => { 2 => ["Twix", "Kinder"] }
El transform_valuescódigo aquí es probablemente un poco confuso, pero una cosa importante a entender es que muchas veces, llamar a métodos Enumerables en hashes los convierte en [[key1, val1], [key2, val2]]matrices:
counts_by_input.group_by { |input, count| count }
# => { 2 => [["Twix", 2], ["Kinder", 2]] }
Es por eso que llamamos transform_values { |keyvals| keyvals.map(&:first) }después para obtener nuestro formato deseado{ 2 => ["Twix", "Kinder"] }
De todos modos, en este punto conseguir nuestro resultado es muy fácil:
inputs_by_count[inputs_by_count.keys.max]
# => ["Twix", "Kinder"]
Sé que probablemente todo esto parezca un poco loco, pero cuando se familiarice con los métodos de Enumerable podrá realizar este tipo de transformación de datos con bastante fluidez.
Tl; dr, dame el codez
inputs = []
loop do
input = gets.chomp.to_i
break if input.zero?
inputs << input
end
inputs_by_count = inputs.
group_by(&:itself).
transform_values(&:count).
group_by { |keyvals, count| count }.
transform_values { |keyvals| keyvals.map(&:first) }
top_count = inputs_by_count.keys.max
inputs_by_count[top_count]
# => ["Twix", "Kinder"]
Qué tal algo como esto:
maximum = a.max # => 2
top_selling_bars = a.map.with_index { |e, i| b[i] if e == maximum }.compact # => ['Kinder', 'Twix']
p top_selling_bars # => ['Kinder', 'Twix']
Si usted tiene
a = [2, 2, 0,]
b = ['Kinder', 'Twix', 'Mars']
Puede calcular el valor máximo en a através de:
max = a.max #=> 2
y encuentre todos los elementos correspondientes a ese valor a través de:
b.select.with_index { |_, i| a[i] == max }
#=> ["Kinder", "Twix"]