Извлечь элементы между 2 числами в Ruby - PullRequest
3 голосов
/ 20 апреля 2020

Проблема:

  • Учитывая массив чисел в Ruby, вернуть группы чисел, которые появляются между 1 и 2.
  • Числа 1 и 2 не отображаются между другими 1 и 2 (нет подмножеств подмножеств).

Пример 1

вход: [1, 3, 2, 1, 4, 2]

вывод: [[1, 3, 2], [1, 4, 2]]

Пример 2

input: [0, 1, 3, 2, 10, 1, 5, 6, 7, 8, 7, 5, 2, 3, 1, -400, 2, 12, 16]

output: [ [1, 3, 2], [1, 5, 6, 7, 8, 7, 5, 2], [1, -400, 2] ]

Моя догадка это использовать комбинацию #chunk и #drop_while или генератор.

Заранее спасибо.

Ответы [ 5 ]

1 голос
/ 20 апреля 2020

Для всех, кто хочет прогуляться по пляжу, но по понятным причинам не может:

class Flipflop

  def initialize(flip, flop) #flip and flop being boolean-returning lambdas
    @state = false
    @flip  = flip
    @flop  = flop
  end

  def flipflop(x) #logic taken from The Ruby Programming Language page 111
    if !@state
      result = @flip[x]
      if result
        @state = !@flop[x]
      end
      result
    else
      @state = !@flop[x]
      true
    end
  end

end

ff = Flipflop.new( ->(x){x == 1}, ->(x){x == 2} )
input = [0, 1, 3, 2, 10, 1, 5, 6, 7, 8, 7, 5, 2, 3, 1, -400, 2, 12, 16]

res = input.select{|el| ff.flipflop(el) }.slice_before(1) #an Enumerator
p res.to_a
# =>[[1, 3, 2], [1, 5, 6, 7, 8, 7, 5, 2], [1, -400, 2]]

Для струн ff = Flipflop.new( ->(x){x.chomp == "BEGIN"}, ->(x){x.chomp == "END"} ) или что-то подобное должно работать.

1 голос
/ 20 апреля 2020

Вы можете использовать chunk и Ruby * триггер оператор:

input = [0, 1, 3, 2, 10, 1, 5, 6, 7, 8, 7, 5, 2, 3, 1, -400, 2, 12, 16]

input.chunk { |i| true if i==1..i==2 }.each { |_, ary| p ary }

Выход:

[1, 3, 2]
[1, 5, 6, 7, 8, 7, 5, 2]
[1, -400, 2]
1 голос
/ 20 апреля 2020

Поскольку вы прокомментировали и добавили, что вы на самом деле читаете файл, я удалил свой старый ответ (который в любом случае был ошибочным, как указывал @Stefan) и скрылся с этим. Вы можете вставить это в файл и запустить его, DATA IO содержит все, что появляется после __END__. В вашем приложении вы должны заменить его своим файлом.

class Chunker
  BEGIN_INDICATOR = "BEGIN"
  END_INDICATOR = "END"

  def initialize(io)
    @io = io
  end

  def each
    return enum_for(:each) if !block_given?

    chunk = nil
    while !io.eof? do
      line = io.readline.chomp
      if line == BEGIN_INDICATOR
        chunk = []
        chunk << line
      elsif line == END_INDICATOR
        chunk << line
        yield chunk.freeze
        chunk = nil
      elsif chunk
        chunk << line
      end
    end
  end

  private

  attr_reader :io
end

chunker = Chunker.new(DATA)


chunker.each do |chunk|
  p chunk
end

# or, thanks to the `return enum_for(:each) if !block_given?` line:

chunker.each.with_index do |chunk, index|
  p "at #{index} is #{chunk}"
end



__END__
ignore
BEGIN
some
thing
END
BEGIN
some
other
thing
END
maybe ignore as well
´´´

You could enhance it to throw EOF when `each` is called multiple times or whatever suits your needs.
1 голос
/ 20 апреля 2020

Похоже на вопрос интервью. Я объясню самый простой алгоритм, о котором я только могу подумать:

Вы один раз пропустили oop через массив и построите вывод, как вы go. Когда вы встречаете 1, вы сохраняете его и последующие числа в другом временном массиве. Когда вы встречаете 2, вы помещаете массив в выходной массив. Крайние случаи:

  • еще один 1 после начала создания временного массива
  • a 2, когда у вас нет временного массива

Первый случай прост, всегда создавайте новый временный массив, когда вы встречаете 1. Во втором случае вы должны проверить, есть ли у вас какие-либо элементы во временном массиве, и только добавить временный массив к вашему выводу, если он не пустой.

Это должно помочь вам начать.

0 голосов
/ 20 апреля 2020

Это опция, использующая [Enumerable # slice_when] [1]:

ary1 = [1, 3, 2, 1, 4, 2]
ary2 = [0, 1, 3, 2, 10, 1, 5, 6, 7, 8, 7, 5, 2, 3, 1, -400, 2, 12, 16]

Например:

stop = [1, 2]
ary2.slice_when{ |e| stop.include? e }
    .each_slice(2).map { |a, b| b.unshift(a.last) if b }
    .reject { |e| e.nil? || (e.intersection stop).empty? }

#=> [[1, 3, 2], [1, 5, 6, 7, 8, 7, 5, 2], [1, -400, 2]]

Другая опция

Более многословно, но более четко, учитывая ввод:

input =  %w(b a b c a b c a c b c a c a)
start = 'a'
stop  = 'b'

Используя Enumerable#each_with_object, почему бы не использовать старый добрый if then else?:

tmp = []
pickup = false
input.each_with_object([]) do |e, res|
  if e == start
    pickup = true
    tmp << e
  elsif pickup && e == stop
    tmp << e
    res << tmp
    tmp = []
    pickup = false
  elsif pickup
    tmp << e
  end
end

#=> [["a", "b"], ["a", "b"], ["a", "c", "b"]]

  [1]: https://ruby-doc.org/core-2.7.0/Enumerable.html#method-i-slice_when
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...