Sprachprofi
Sprachprofi

Reputation: 1259

Ruby: How to get the indices of the first x array elements that match a condition?

I have two huge arrays of sentences, one in German and one in English. I will search through the German sentences for sentences that contain a certain word and if they do, I will check if there is an equivalent English sentence (using a hash with connection information). However, if the user is looking for a very common word, I don't want to return every single sentence that contains it but only the first x matches and stop searching then.

If I do german_sentences.index { |sentence| sentence.include?(word) } I get only one match at a time. If I use german_sentences.keep_if { |sentence| sentence.include?(word) } I get all matches, but also lose the index information, which is really critical for this.

I am now using a custom loop with each_with_index and break once the maximum has been reached, but I really feel that I must be missing some existing solution, at least something that gives a limited number of matches (even if not their indices)...

Upvotes: 2

Views: 133

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110665

If your need is not a one-off, you could use Module#refine, rather than monkeypatching Array). refine was added to v2.0 experimentally, then changed considerably in v. 2.1. One of the restrictions in the use of refine is: "You may only activate refinements at top-level...", which evidently prevents testing in Pry and IRB.

module M
  refine Array do
    def select_indices_first(n)
      i = 0
      k = 0
      a = []
      return a if n == 0
      each { |x| (a << i; k += 1) if yield(x); break if k == n; i += 1 }
      a
    end

    def select_first(n) # if you wanted this also...
      k = 0
      a = []
      return a if n == 0
      each { |x| (a << x; k += 1) if yield(x); break if k == n }
      a
    end
  end
end

using M

sentences = ["How now brown", "Cat", "How to guide", "How to shop"]
sentences.select_indices_first(0)  {|s| s.include?("How")} # => []
sentences.select_indices_first(1)  {|s| s.include?("How")} # => [0]
sentences.select_indices_first(2)  {|s| s.include?("How")} # => [0, 2]
sentences.select_indices_first(3)  {|s| s.include?("How")} # => [0, 2, 3]
sentences.select_indices_first(99) {|s| s.include?("How")} # => [0, 2, 3]

sentences.select_first(2) {|s| s.include?("How")} 
  # => ["How now brown", "How to guide"]

Upvotes: 1

sawa
sawa

Reputation: 168081

german_sentences
.each_index
.lazy
.select{|i| german_sentences[i].include?(word)}
.first(n)

Upvotes: 4

Related Questions