Why does using a regex and .scan produce these results? - ruby

>> "aaaaaafbfbfsjjseew".scan(/(.)/)
=> [["a"], ["a"], ["a"], ["a"], ["a"], ["a"], ["f"], ["b"], ["f"], ["b"], ["f"], ["s"], ["j"], ["j"], ["s"], ["e"], ["e"], ["w"]]
>> "aaaaaafbfbfsjjseew".scan(/((.))/)
=> [["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["f", "f"], ["b", "b"], ["f", "f"], ["b", "b"], ["f", "f"], ["s", "s"], ["j", "j"], ["j", "j"], ["s", "s"], ["e", "e"], ["e", "e"], ["w", "w"]]
>> "aaaaaafbfbfsjjseew".scan(/((.)\2*)/)
=> [["aaaaaa", "a"], ["f", "f"], ["b", "b"], ["f", "f"], ["b", "b"], ["f", "f"], ["s", "s"], ["jj", "j"], ["s", "s"], ["ee", "e"], ["w", "w"]]
>> "aaaaaafbfbfsjjseew".scan(/((.)\1*)/)
=> [["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["f", "f"], ["b", "b"], ["f", "f"], ["b", "b"], ["f", "f"], ["s", "s"], ["j", "j"], ["j", "j"], ["s", "s"], ["e", "e"], ["e", "e"], ["w", "w"]]
>> "aaaaaafbfbfsjjseew".scan(/((.)\3*)/)
=> [["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["a", "a"], ["f", "f"], ["b", "b"], ["f", "f"], ["b", "b"], ["f", "f"], ["s", "s"], ["j", "j"], ["j", "j"], ["s", "s"], ["e", "e"], ["e", "e"], ["w", "w"]]

From the fine manual:
str.scan(pattern) → array
[...]
If the pattern contains groups, each individual result is itself an array containing one entry per group.
This one:
"aaaaaafbfbfsjjseew".scan(/(.)/)
has a group so you get an array of arrays: each individual result is a single element array.
The next one:
"aaaaaafbfbfsjjseew".scan(/((.))/)
has two groups which happen to have the same value so you get two identical elements in your individual result arrays.
The third one:
"aaaaaafbfbfsjjseew".scan(/((.)\2*)/)
again contains two groups but also contains a back-reference to the inner group so the outer group (AKA the first group) gobbles up duplicates and you get ["aaaaaa", "a"], ["jj", "j"], and ["ee", "e"].
The fourth one:
"aaaaaafbfbfsjjseew".scan(/((.)\1*)/)
just tries to switch the back-reference to the outer group but \1 isn't defined inside group 1 so it is equivalent to /((.))/.
The fifth one:
"aaaaaafbfbfsjjseew".scan(/((.)\3*)/)
tries to refer to a non-existant group (group 3 when there are only two groups) so it behaves the same as /((.))/.

"aaaaaafbfbfsjjseew".scan(/(.)/) means the string can be splitted into individual array of strings.
Here parenthesis tells that it's an array, and the .-symbol in parenthesis represents number of characters in that individual string of array.
If we write for suppose "hellovenkat".scan(/(...)/) , this results
[["hel"],["lov"],["enk"]]. It doesn't give the last index, because it can not contain three characters.
If we give "hello venkat".scan(/(...)/), this results as following.
Ans: [["hel"], ["lo "], ["ven"], ["kat"]].

Related

Add elements of an array to a specific index of each array within an array of arrays

I have an array of arrays that serves as a table of data, and am trying to add an extra array as though adding an extra column to the table.
For simplicity, suppose the first array is a
a = [["a", "b", "c"], ["e", "f", "g"], ["i", "j", "k"]]
and the second array is b
b = ["d", "h", "l"]
the desired output is:
c = [["a", "b", "c", "d"], ["e", "f", "g", "h"], ["i", "j", "k", "l"]]
I have tried using + and some attempts at using map but cannot get it
You can zip them together which will create array elements like [["a", "b", "c"], "d"] and then just flatten each element.
a.zip(b).map(&:flatten)
#=> [["a", "b", "c", "d"], ["e", "f", "g", "h"], ["i", "j", "k", "l"]]
Answer improved as per Cary's comment. I think he's done Ruby stuff before.
a.zip(b).map { |arr,e| arr + [e] }
#=> [["a", "b", "c", "d"],
# ["e", "f", "g", "h"],
# ["i", "j", "k", "l"]]
The intermediate calculation is as follows.
a.zip(b)
#=> [[["a", "b", "c"], "d"],
# [["e", "f", "g"], "h"],
# [["i", "j", "k"], "l"]]
See Array#zip.
You can use #each_with_index combined with #map to iterate over the array a and append respective elements of array b
> a.each_with_index.map{|e, i| e | [b[i]] }
=> [["a", "b", "c", "d"], ["e", "f", "g", "h"], ["i", "j", "k", "l"]]

How to make all possible pairs from an array

a = ["a","b","c"]
a.each_cons(2).to_a # => [["a", "b"], ["b", "c"]]
I want three possible pairs from this array
You can use Array#permutation to generate sub-arrays with all combination.
a.permutation(2).to_a
# => [["a", "b"], ["a", "c"], ["b", "a"], ["b", "c"], ["c", "a"], ["c", "b"]]
Following this you can pick 3 random arrays using Array#sample (assuming you want to pick random sub-arrays). Here:
a.permutation(2).to_a.sample(3)
# => [["c", "b"], ["c", "a"], ["b", "c"]]
Try this:
a = ["a","b","c"]
a.permutation(2).to_a.take(3)
# => [["a", "b"], ["a", "c"], ["b", "a"]]
a = ["a","b","c"]
a.combination(2).to_a # => [["a", "b"], ["a", "c"], ["b", "c"]]

Convert multiple level array to single level array?

I want to convert this array
[[["b", "c"], ["c", "d"]], [["v", "e"], ["r", "g"]]]
into
[["b", "c"], ["c", "d"], ["v", "e"], ["r", "g"]]
How can I convert this ?
Array#flatten takes an optional level:
The optional level argument determines the level of recursion to flatten
Example:
[[["b", "c"], ["c", "d"]], [["v", "e"], ["r", "g"]]].flatten(1)
#=> => [["b", "c"], ["c", "d"], ["v", "e"], ["r", "g"]]
arr = []
a = [[["b", "c"], ["c", "d"]], [["v", "e"], ["r", "g"]]]
a.map{|x| x.map{|y| arr << y}}
puts arr

How to flatten innermost array

I have this array:
[[["a", "c"], "e"],
[["a", "c"], "f"],
[["a", "c"], "g"],
[["a", "d"], "e"],
[["a", "d"], "f"],
[["a", "d"], "g"],
[["b", "c"], "e"],
[["b", "c"], "f"],
[["b", "c"], "g"],
[["b", "d"], "e"],
[["b", "d"], "f"],
[["b", "d"], "g"]]
I would like to turn it into this:
[["a", "c", "e"],
["a", "c", "f"],
["a", "c", "g"],
["a", "d", "e"],
["a", "d", "f"],
["a", "d", "g"],
["b", "c", "e"],
["b", "c", "f"],
["b", "c", "g"],
["b", "d", "e"],
["b", "d", "f"],
["b", "d", "g"]]
How can I do this with Ruby? I have looked at flatten by it seems to work from the outside in, not inside out.
You could use flatten and map:
ar.map! {|i| i.flatten}
# => [["a", "c", "e"],
# ["a", "c", "f"],
# ["a", "c", "g"],
# ["a", "d", "e"],
# ["a", "d", "f"],
# ["a", "d", "g"],
# ["b", "c", "e"],
# ["b", "c", "f"],
# ["b", "c", "g"],
# ["b", "d", "e"],
# ["b", "d", "f"],
# ["b", "d", "g"]]
Another one-liner would be :
ar.map!(&:flatten)
# => [["a", "c", "e"],
# ["a", "c", "f"],
# ["a", "c", "g"],
# ["a", "d", "e"],
# ["a", "d", "f"],
# ["a", "d", "g"],
# ["b", "c", "e"],
# ["b", "c", "f"],
# ["b", "c", "g"],
# ["b", "d", "e"],
# ["b", "d", "f"],
# ["b", "d", "g"]]
or try arr.each {|i| i.flatten!}

Merging arrays without losing original order, ruby

I have an array structure that looks like:
a=[
[['a','A'],['b','B'],['c','C']],
[['d','D'],['e','E'],['f','F']]
]
How to merge inner two arrays so the new structure will be Array of arrays
[
['a','A'],['b','B'],['c','C'],['d','D'],['e','E'],['f','F']
]
Tried
a.inject([]){|k,v| v | k} # but order gets changed
=> [["d", "D"], ["e", "E"], ["f", "F"], ["a", "A"], ["b", "B"], ["c", "C"]]
How can i get desired result without loosing the order.
Tips, comments, suggestions, please?
Thnx.
array.flatten takes a parameter:
a.flatten(1) #[["a", "A"], ["b", "B"], ["c", "C"], ["d", "D"], ["e", "E"], ["f", "F"]]
Try this:
a.inject([]){|k,v| k|v}

Resources