Найдите индекс несоответствия в массиве

У меня есть массив, который должен содержать одно и то же значение, и если есть несоответствия, я хочу получить индекс этих несоответствий.

Пример:

[1,1,1,1,3,1,1,1,2,1,1,1]

Выход:

[4, 8]

Как лучше всего это сделать в Ruby/Rails?

🤔 А знаете ли вы, что...
Фреймворк предоставляет множество инструментов для оптимизации производительности, включая использование кэширования и управление запросами.


114
6

Ответы:

что-то вроде:

def find_non_matching_indexes(array, value)
  # Use `each_with_index` to iterate through the array with indexes
  array.each_with_index.select do |element, index|
    # Select elements where the value is not the given value
    element != value
  end.map(&:last) # Extract only the indexes from the selected elements
end

def find_mismatch_indices(arr, main_value)
  arr.each_index.select { |i| arr[i] != main_value }
end

my_array = [1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1]
main_value = my_array.tally.max_by { |_, count| count }.first
result = find_mismatch_indices(my_array, main_value)

puts "Indices of mismatches: #{result.inspect}"

Выход

Indices of mismatches: [4, 8]

Решено

Вы можете получить наиболее распространенный элемент с помощью tally и max_by:

arr = [1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1]

most_common = arr.tally.max_by(&:last).first
#=> 1

tally возвращает хэш, содержащий количество вхождений каждого элемента ({1=>10, 3=>1, 2=>1}), max_by(&:last) возвращает пару с наибольшим количеством вхождений, а first возвращает значение этого элемента. (при условии, что всегда есть один наиболее распространенный элемент)

Чтобы получить индексы, вы можете использовать filter_map:

arr.each_with_index.filter_map { |e, i| i if e != most_common }
#=> [4, 8]

each_with_index возвращает каждому элементу соответствующий индекс. filter_map выбирает правдивые результаты из блока, который возвращает индекс элемента, если элемент не равен 1. (и nil в противном случае, который отбрасывается)


Нам нужно преобразовать данные, чтобы определить, где и как часто встречаются элементы.

>  a = [1,1,1,1,3,1,1,1,2,1,1,1]
=> [1, 1, 1, 1, 3, 1, 1, 1, 2, 1, 1, 1]
> b = a.each_with_index.sort_by(&:first).group_by(&:first).transform_values { _1.map(&:last) }
=> {1=>[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 2=>[10], 3=>[11]}

Затем нам просто нужно исключить все элементы, кроме самого распространенного, и извлечь индексы.

> b.sort_by(&:length)[..-2].map { _1[1][0] }.sort
=> [4, 8]

Просто еще одна версия:

[1,1,1,1,3,1,1,1,2,1,1,1]
   .each_with_object(Hash.new { |hash, key| hash[key] = [] })
   .with_index { |(e, hash), i| hash[e] << i } # collect elements with their index
   .values                                     # only return the indexes
   .sort_by(&:size)                            # sort indexes arrays by size
   .slice(..-2)                                # return all but the longest
   .flatten                                    # flatten
#=> [4, 8]

Если вы используете tally и max_by, вы учитываете только один наиболее распространенный вариант.

Предположим, у вас есть эти массивы:

arr1=[1,1,1,1,3,1,1,1,2,1,1,1]  # should be [4,8]
arr2=[1,1,1,3,3,3,4,4,4,2] # should be [9]?
arr3=[1,1,1,1,1,1] # should be []?
arr4=[1,1,1,2,2,2,3,3,3] # should be []?

Затем рассмотрите этот подход, который позволяет использовать более одного значения или отсутствие значения как «наиболее распространенного»:

def index_of_minority(arr)
    tal=arr.tally.sort_by(&:last).reverse
    most_common,rest=tal.partition{|e,cnt| cnt==tal[0][1]}.map{|sa| sa.to_h}
    arr.each_with_index.select{|e,i| rest.key?(e) }.map(&:last)
end    

Затем с этими массивами:

[arr1,arr2,arr3,arr4].each{|arr| p index_of_minority(arr) }
[4, 8]
[9]
[]
[]