Ruby Working on Array Elements in Groups of Four

ruby working on array elements in groups of four

You can enumerate in groups of 4 for an array:

>> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].each_slice(4) {|a| p a}
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10, 11, 12]

So you can try something like

elements.each_slice(4) do | batch |
batch.each do | element |
threads.push(Thread.new{process(element)}}

end
(do stuff to check to see if the threads are done, otherwise wait )
end

Its may not be what you need, though - I have been up since 3 AM and I only had a couple of hours sleep. :/

Group Elements by Each in Array

Here is another way :

array = [1, 1, 2, 3, 3, 1, 5, 6, 2]
array.group_by(&:itself).values
# => [[1, 1, 1], [2, 2], [3, 3], [5], [6]]

Look #itself method.

If you have not asked above, then #slice_when is your way to go :

array.slice_when { |i,j|  i != j }.to_a
# => [[1, 1], [2], [3, 3], [1], [5], [6], [2]]
array.slice_when { |i,j| i != j }.each { |n| p "do_something_with_#{n}" }
# "do_something_with_[1, 1]"
# "do_something_with_[2]"
# "do_something_with_[3, 3]"
# "do_something_with_[1]"
# "do_something_with_[5]"
# "do_something_with_[6]"
# "do_something_with_[2]"

Group by, array of arrays in ruby

Use following

some_array.group_by{|a| [a[0], a[1]]}
.map{|key, value| key + [value.map(&:last)]}
.flatten(1)

For multiple values in group by

2.3.1 :046 > some_array = [["FANUC CORP", "100048", 9], ["FANUC CORP", "100048", 26]
, ["FANUC CORP", "100048", 23], ["FANUC CORP", "100048", 111]
, ["FANUC CORP", "100049", 19],["FANUC CORP", "100049", 126],
["FANUC CORP", "100049", 123], ["FANUC CORP", "100049", 1111]]
=> [["FANUC CORP", "100048", 9], ["FANUC CORP", "100048", 26],
["FANUC CORP", "100048", 23], ["FANUC CORP", "100048", 111],
["FANUC CORP", "100049", 19], ["FANUC CORP", "100049", 126],
["FANUC CORP", "100049", 123], ["FANUC CORP", "100049", 1111]]

2.3.1 :047 > some_array.group_by{|a| [a[0], a[1]]}
.map{|key, value| key + [value.map(&:last)]}
.flatten(1)
=> ["FANUC CORP", "100048", [9, 26, 23, 111],
"FANUC CORP", "100049", [19, 126, 123, 1111]]

Group every n-th element of array

Nick Veys' answer is most straightforward, but here is another way.

array.group_by.with_index{|_, i| i % 3}.values
#=> [[1, 4, 7], [2, 5, 8], [3, 6, 9]]

Selecting group of elements from array which satisfies specific condition

if the order doesn't matter (I mean ([4,1]==[4,1])) I have a better solution to bruteforcing combinations.

This is a bruteforcing algorithm

def bruteforcing(arr)
arr.combination(2).find_all{ |x, y| x + y == 5 }.uniq
end

This is a better solution (I'ts just an example you could improve). The main idea is to order the Array and search pair by the opposite extremes at first, and stop the search if the sum of values is mayor than 5.

    def search(arr)
ret=[]
arr.sort!

while arr != []
current = arr.pop
arr.each.with_index do |value, index|
if current + value == 5
ret << [value,current]
arr.delete_at(index)
break
elsif current+value > 5
break
end
end
end
ret
end

This is my search.rb (with benchmark)

require "benchmark"

def bruteforcing(arr)
arr.combination(2).find_all{ |x, y| x + y == 5 }.uniq
end

def search(arr)
ret=[]
arr.sort!

while arr != []
current = arr.pop
arr.each.with_index do |value, index|
if current + value == 5
ret << [value,current]
arr.delete_at(index)
break
elsif current+value > 5
break
end
end
end
ret
end

def bench_times(n)
Benchmark.bm do |x|
puts "behc n times #{n}."
x.report { n.times{bruteforcing( [1,2,3,4,3,2,4,1,2] ) } }
x.report { n.times{ search( [1,2,3,4,3,2,4,1,2] ) } }
end
end

def bench_elements(n)
puts "bench with #{n} elements."
Benchmark.bm do |x|
a=[]
1_000.times { a<<rand(1..4) }
x.report { bruteforcing(a) }
a=[]
1_000.times { a << rand(1..4) }
x.report { search(a) }
end
end

puts bruteforcing([1,2,3,4,3,2,4,1,2]).to_s
puts search([1,2,3,4,3,2,4,1,2]).to_s

bench_times 1
bench_times 5
bench_times 1_000
bench_times 1_000_000

bench_elements(100)
bench_elements(1_000)
bench_elements(100_000)
bench_elements(1_000_000)

The output:

[[1, 4], [2, 3], [3, 2], [4, 1]]
[[1, 4], [1, 4], [2, 3], [2, 3]]
user system total real
behc n times 1.
0.000000 0.000000 0.000000 ( 0.000036)
0.000000 0.000000 0.000000 ( 0.000013)
user system total real
behc n times 5.
0.000000 0.000000 0.000000 ( 0.000118)
0.000000 0.000000 0.000000 ( 0.000037)
user system total real
behc n times 1000.
0.020000 0.000000 0.020000 ( 0.017804)
0.010000 0.000000 0.010000 ( 0.006673)
user system total real
behc n times 1000000.
16.580000 0.020000 16.600000 ( 16.583692)
5.970000 0.000000 5.970000 ( 5.968241)
bench with 100 elements.
user system total real
0.210000 0.010000 0.220000 ( 0.213506)
0.000000 0.000000 0.000000 ( 0.000863)
bench with 1000 elements.
user system total real
0.210000 0.000000 0.210000 ( 0.212349)
0.000000 0.000000 0.000000 ( 0.001539)
bench with 100000 elements.
user system total real
0.200000 0.000000 0.200000 ( 0.201456)
0.000000 0.000000 0.000000 ( 0.001067)
bench with 1000000 elements.
user system total real
0.190000 0.010000 0.200000 ( 0.199400)
0.010000 0.000000 0.010000 ( 0.000801)

How to group array elements by index?

You can use slice_after to slice the array after each item whose index is in idx:

idx = [1, 5, 7]
arr = %w[a b c d e f g h i j k]

arr.enum_for(:slice_after).with_index { |_, i| idx.include?(i) }.to_a
#=> [["a", "b"], ["c", "d", "e", "f"], ["g", "h"], ["i", "j", "k"]]

That enum_for is (unfortunately) needed to chain slice_after and with_index.

Ruby split array into X groups

You can make your own method, here's a basic idea:

class Array
def my_group(x)
start = 0
size = (self.size() / Float(x)).ceil
while x > 0
yield self[start, size]
size = ((self.size() - 1 - start) / Float(x)).ceil
start += size
x -= 1
end
end
end

%w(1 2 3 4 5 6 7 8 9 10).my_group(3) {|group| p group}
# =>["1", "2", "3", "4"]
# =>["4", "5", "6"]
# =>["7", "8", "9"]

How to group identical elements in Ruby array

Here is how to do that in Ruby.

array.group_by{ |x| x }.values

How to iterate over an array in overlapping groups of n elements?

You can add nil as the first element of your arr and use Enumerable#each_cons method:

arr.unshift(nil).each_cons(2).map { |first, second| [first, second] }
# => [[nil, "one"], ["one", "two"], ["two", "three"]]

(I'm using map here to show what exactly is returned on each iteration)

Ruby group_by in array of arrays

fruits.group_by {|(fruit, day)| fruit }.map {|fruit, match| [fruit, match.count] }


Related Topics



Leave a reply



Submit