1

I want to split a string to an array which include each 2 word of original string as below:

Ex:
str = "how are you to day"
output = ["how are", "are you", "you to", "to day"]

Any one can give solution? thank so much!

1

4 Answers 4

2

Input

str = "how are you to day"

Code

p str.split(/\s/)
     .each_cons(2)
     .map { |str| str.join(" ") }

Output

["how are", "are you", "you to", "to day"]
Sign up to request clarification or add additional context in comments.

9 Comments

Is the “map(:&itself)” basically the same as calling “to_a”?
@melcher No! map(&:itself) = map{|x| x}
The split argument isn’t really necessary for the example given.
split returns an array. You can save memory by returning an enumerator if you replace str.split(/\s/) (or just str.split) with gsub(/\w+/).
@Rajagopalan, you're welcome. Nothing against your suggested approach at all, but for what its worth, the alternative method I posted below is about 20% faster than even using str.split in your suggested approach.
|
1

Here is one approach, which uses a regex trick to duplicate the second through second to last words in the input string:

input = "how are you to day"
input = input.gsub(/(?<=\s)(\w+)(?=\s)/, "\\1 \\1")
output = input.scan(/\w+ \w+/).flatten
puts output

This prints:

how are
are you
you to
to day

Comments

1

Here are a couple ways to do that. Both use the form of String#gsub that takes a regular expression as its argument and no block, returning an enumerator. This form of gsub merely generates matches of the regular expression; it has nothing to do with string replacement.

str = "how are you to day"

Use a regular expression that contains a positive lookahead

r = /\w+(?=( \w+))/
str.gsub(r).with_object([]) { |s,a| a << s + $1 }
  #=> ["how are", "are you", "you to", "to day"]

I've chained the enumerator str.gsub(r) to Enumerator#with_object. String#gsub is a convenient replacement for String#scan when the regular expression contains capture groups. See String#scan for for an explanation of how it treats capture groups.

We can write the regular expression in free-spacing mode to make it self-documenting.

r = /
    \w+       # match >= 1 word characters
    (?=       # begin a positive lookahead
      ( \w+)  # match a space followed by >= 1 word characters and save
              # to capture group 1
    )         # end positive lookahead
    /x        # invoke free-spacing regex definition mode

Enumerate pairs of successive words in the sting

enum = str.gsub(/\w+/)
loop.with_object([]) do |_,a|
  a << enum.next + ' ' + enum.peek
end
  #=> ["how are", "are you", "you to", "to day"]

See Enumerator#next and Enumerator#peek. After next returns the last word in the string peek raises a StopIteration exception which is handled by loop by breaking out of the loop and returning the array a. See Kernel#loop.

3 Comments

You are the real master in Ruby!
@Rajagopalan, thanks, but you are misguided! I'm just a Ruby hobbiest.
That's why you are more efficient!
0

Here’s another option:

str = "how are you to day"
arr = str.split
new_arr = []
(arr.length-1).times {new_arr.push(arr[0..1].join(" ")); arr.shift}

print new_arr #=> ["how are", "are you", "you to", "to day"]

1 Comment

...or drop new_arr = [] and replace the next line with (arr.length-1).times.map { |i| arr[i] + ' ' + arr[i+1] }.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.