Converting Ruby Array to Array of Consecutive Pairs

Converting ruby array to array of consecutive pairs

Use Enumerable#each_slice:

y = x.each_slice(2).to_a
#=> [[:a, :b], [:c, :d]]

[0, 1, 2, 3, 4, 5].each_slice(2).to_a
#=> [[0, 1], [2, 3], [4, 5]]

Array into ranges of consecutive numbers

Here's a solution to the same question you're asking. The linked code does a bit more work than you require (the numbers don't need to be sorted, or consecutive), but it'll do the trick. Or, you could use this code, suggested by @NewAlexandria :

class Array
def to_ranges
compact.sort.uniq.inject([]) do |r,x|
r.empty? || r.last.last.succ != x ? r << (x..x) : r[0..-2] << (r.last.first..x)
end
end
end

Best way to turn an array into a 2D array in Ruby

Use Enumerable#each_slice:

each_slice(n) { ... } → nil

each_slice(n) → an_enumerator

Iterates the given block for each slice of n elements. If no block is given, returns an enumerator.

So you'd say:

s.each_slice(2).to_a

or

s.each_slice(2).entries

Iterate pairwise through a ruby array

You are looking for each_cons:

(1..6).each_cons(2) { |a, b| p a: a, b: b }
# {:a=>1, :b=>2}
# {:a=>2, :b=>3}
# {:a=>3, :b=>4}
# {:a=>4, :b=>5}
# {:a=>5, :b=>6}

Consecutive join operations on an Array in a single line of code

You can use map after each_slice, rather than using <<:

[1,2,3,4,5,6].each_slice(2).map {|a| a.join("\t")}.join("<br\>")

Ruby array access 2 consecutive(chained) elements at a time

Ruby reads your mind. You want cons ecutive elements?

[1, 2, 3, 4, 5, 6, 7, 8, 9].each_cons(2).to_a
# => [[1, 2], [2, 3], [3, 4], [4, 5], [5, 6], [6, 7], [7, 8], [8, 9]]

Ruby array to HTML table

more or less stateless :-)

a = [["a", 1, 2 ,3], ["a", 1, 2 ,3], ["a", 1, 2 ,3],
["b", 1, 2 ,3], ["b", 1, 2 ,3], ["b", 1, 2 ,3], ["c", 1, 2 ,3]]

grouped = a.group_by{|t| t[0]}.values
header = "<tr><td>Name</td> <td>Length</td> <td>Width</td> <td>Depth</td> </tr>"
table = grouped.map do |portion|
"<table>\n" << header << "\n<tr>" << portion.map do |column|
"<td>" << column.map do |element|
element.to_s
end.join("</td><td>") << "</td>"
end.join("</tr>\n<tr>") << "</tr>\n</table>\n"
end.join("\n")
puts table

Challenge: combine into an array only sequential keys of specific value in Ruby

Code

def combine_only_blah_blah_blah(list, key)
list.flat_map(&:to_a).
slice_when { |(k1,_),(k2,_)| k1 != k2 }.
flat_map do |a|
k = a.first.first
(a.size > 1 && k == key) ? { k=>a.map(&:last) } : a.map { |b| [b].to_h }
end
end

Example

list = [{a: 1}, {a: 2}, {b: 3}, {b: 4}, {c: 5}, {a: 6}]
key = :a

combine_only_blah_blah_blah(list, key)
#=> [{:a=>[1, 2]}, {:b=>3}, {:b=>4}, {:c=>5}, {:a=>6}]

Explanation

For list and key above, the steps are as follows.

b = list.flat_map(&:to_a)
#=> [[:a, 1], [:a, 2], [:b, 3], [:b, 4], [:c, 5], [:a, 6]]
e = b.slice_when { |(k1,_),(k2,_)| k1 != k2 }
#=> #<Enumerator: #<Enumerator::Generator:0x007f9bda968c50>:each>

We can see what elements will be generated by this enumerator by converting it to an array.

e.to_a
#=> [[[:a, 1], [:a, 2]], [[:b, 3], [:b, 4]], [[:c, 5]], [[:a, 6]]]

Continuing,

e.flat_map do |a|
k = a.first.first
(a.size > 1 && k == key) ? { k=>a.map(&:last) } : a.map { |b| [b].to_h }
end
#=> [{:a=>[1, 2]}, {:b=>3}, {:b=>4}, {:c=>5}, {:a=>6}]

The first element generated by e that is passed to flat_map's block is

a = e.next
#=> [[:a, 1], [:a, 2]]

and the block calculation is as follows.

k = a.first.first
#=> :a
(a.size > 1 && k == key)
#=> (2 > 1 && :a == :a)
#=> true

so

{ k=>a.map(&:last) }
#=> {:a=>[1, 2]}

is executed. The next element generated by e and passed to the block, and the subsequent block calculations are as follows.

a = e.next
#=> [[:b, 3], [:b, 4]]
k = a.first.first
#=> :b
(a.size > 1 && k == key)
#=> (2 > 1 && :b == :a)
#=> false
a.map { |b| [b].to_h }
#=> [{:b=>3}, {:b=>4}]

Note that when

b = [:b, 3]

[b].to_h
#=> [[:b, 3]].to_h
#=> {:b=>3}

For Ruby versions prior to v2.0, when Array#to_h made its debut, use Hash::[].

Hash[[b]]
#=> {:b=>3}


Related Topics



Leave a reply



Submit