Как чередовать массивы различной длины в Ruby

Если я хочу чередовать набор массивов в Ruby, и каждый массив был такой же длины, мы могли бы сделать так:

a.zip(b).zip(c).flatten

Однако, как мы можем решить эту проблему, если массивы могут быть разных размеров?

Мы могли бы сделать что-то вроде:

def interleave(*args)
  raise 'No arrays to interleave' if args.empty?
  max_length = args.inject(0) { |length, elem| length = [length, elem.length].max }
  output = Array.new
  for i in 0...max_length
    args.each { |elem|
      output << elem[i] if i < elem.length
    }
  end
  return output
end

Но есть ли лучший 'Ruby 'способ, возможно, используя zip или transpose или что-то подобное?

7
задан ChrisInEdmonton 27 August 2010 в 18:50
поделиться

1 ответ

Если в исходных массивах нет nil, вам нужно только расширить первый массив nils, zip автоматически дополнит остальные с ноль. Это также означает, что вы можете использовать compact для очистки от лишних записей, что, надеюсь, более эффективно, чем явные циклы.

def interleave(a,*args)
    max_length = args.map(&:size).max
    padding = [nil]*[max_length-a.size, 0].max
    (a+padding).zip(*args).flatten.compact
end

Вот немного более сложная версия, которая работает, если массивы do содержат ноль

def interleave(*args)
    max_length = args.map(&:size).max
    pad = Object.new()
    args = args.map{|a| a.dup.fill(pad,(a.size...max_length))}
    ([pad]*max_length).zip(*args).flatten-[pad]
end
7
ответ дан 6 December 2019 в 09:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: