Se houver dois elementos máximos em uma matriz?

Nov 25 2020

Neste código se o usuário digitar 2, duas vezes e 1, duas vezes. Então, há dois elementos máximos e ambos Kinder e Twix devem ser impressos. Mas como ? Provavelmente posso fazer isso com o método if, mas isso tornará meu código ainda mais longo. Alguma versão legal? Posso fazer isso com apenas um if?

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
 

Respostas

5 CarySwoveland Nov 25 2020 at 04:15

A questão realmente não tem nada a ver com como o array aé construído.

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 .


Isso também pode ser feito em uma única passagem.

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"]
2 maxpleaner Nov 25 2020 at 04:06

Uma maneira seria a seguinte:

Primeiro, basta separar a coleta de dados da contagem, então vamos apenas reunir os dados nesta etapa:

inputs = []
loop do
  input = gets.chomp.to_i
  break if input.zero?
  inputs << input 
end

Agora podemos registrar as entradas. Se você tem Ruby 2.7, pode simplesmente fazer counts_by_input = inputs.tallypara obter { "Twix" => 2, "Kinder" => 2 }. Caso contrário, minha abordagem preferida é usar group_by com transform_values :

counts_by_input = inputs.group_by(&:itself).transform_values(&:count)
# => { "Twix" => 2, "Kinder" => 2 }

Agora, como iremos extrair valores com base em sua contagem, queremos ter as contagens como chaves. Normalmente podemos inverter o hash, mas isso não funcionará neste caso porque nos dará apenas um valor por chave, e precisamos de vários:

inputs_by_count = counts_by_input.invert
# => { 2 => "Kinder" }
# This doesn't work, it removed one of the values

Em vez disso, podemos usar outro group_by e transform_values(o motivo pelo qual gosto desses métodos é porque eles são muito versáteis ...):

inputs_by_count = counts_by_input.
  group_by { |input, count| count }.
  transform_values { |keyvals| keyvals.map(&:first) }
# => { 2 => ["Twix", "Kinder"] }

O transform_valuescódigo aqui provavelmente é um pouco confuso, mas é importante entender que, muitas vezes, chamar métodos Enumerable em hashes os converte em [[key1, val1], [key2, val2]]arrays:

counts_by_input.group_by { |input, count| count }
# => { 2 => [["Twix", 2], ["Kinder", 2]] }

É por isso que ligamos transform_values { |keyvals| keyvals.map(&:first) }depois para obter o formato desejado{ 2 => ["Twix", "Kinder"] }

De qualquer forma, neste ponto obter nosso resultado é muito fácil:

inputs_by_count[inputs_by_count.keys.max]
# => ["Twix", "Kinder"]

Eu sei que isso provavelmente parece um pouco insano, mas quando você se familiarizar com os métodos do Enumerable, será capaz de fazer esse tipo de transformação de dados com bastante fluência.

Tl; dr, dê-me o código

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"]
2 hashrocket Nov 25 2020 at 04:09

Que tal algo como isso:

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']
1 Stefan Nov 25 2020 at 14:55

Se você tem

a = [2, 2, 0,]
b = ['Kinder', 'Twix', 'Mars']

Você pode calcular o valor máximo em a:

max = a.max #=> 2

e encontre todos os elementos correspondentes a esse valor por meio de:

b.select.with_index { |_, i| a[i] == max }
#=> ["Kinder", "Twix"]