Ruby array to subarray with fall factor - ruby-on-rails

Is there any inbuilt method available to split large array into smaller chunks with dynamic fall factor?
Eg: i=0
src_arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
if batch_size = 5 and fall_factor = 1, first chunk should be [1, 2, 3, 4, 5] and subsequent array chunks should start from start_index = i * (batch_size - fall_factor). ie, start_index will be 0, 4, 8, 12, and
result: [1, 2, 3, 4, 5]
[5, 6, 7, 8, 9]
[9, 10, 11, 12, 13]
[13, 14]
if fall_factor = 2 result should be as below
[1, 2, 3, 4, 5]
[4, 5, 6, 7, 8]
[7, 8, 9, 10, 11]
[10, 11, 12, 13, 14]
I know how to SOLVE this. My question is if any inbuilt method available like each_slice to get this done instead of reinventing.

For example you can use just #step method of Numeric
0.step(src_arr.size - fall_factor - 1, batch_size - fall_factor).map do |ind|
src_arr[ind, batch_size]
end
# fall_factor = 1
# => [[1, 2, 3, 4, 5], [5, 6, 7, 8, 9], [9, 10, 11, 12, 13], [13, 14]]
# fall_factor = 2
# => [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8], [7, 8, 9, 10, 11], [10, 11, 12, 13, 14]]

Code
def doit(arr, batch_size, fall_factor)
arr[batch_size..-1].
each_slice(batch_size-fall_factor).
each_with_object([arr[0,batch_size]]) { |b,c| c << [*c.last[-fall_factor..-1], *b] }
end
Examples
arr = (1..14).to_a
#=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
doit(arr, 5, 1)
#=> [[1, 2, 3, 4, 5], [5, 6, 7, 8, 9], [9, 10, 11, 12, 13], [13, 14]]
doit(arr, 5, 2)
#=> [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8], [7, 8, 9, 10, 11], [10, 11, 12, 13, 14]]
doit(arr, 5, 3)
#=> [[1, 2, 3, 4, 5], [3, 4, 5, 6, 7], [5, 6, 7, 8, 9], [7, 8, 9, 10, 11],
# [9, 10, 11, 12, 13], [11, 12, 13, 14]]
doit(arr, 5, 4)
#=> [[1, 2, 3, 4, 5], [2, 3, 4, 5, 6], [3, 4, 5, 6, 7], [4, 5, 6, 7, 8],
# [5, 6, 7, 8, 9], [6, 7, 8, 9, 10], [7, 8, 9, 10, 11], [8, 9, 10, 11, 12],
# [9, 10, 11, 12, 13], [10, 11, 12, 13, 14]]
Explanation
For arr above and:
batch_size = 5
fall_factor = 2
we have:
a = arr[batch_size..-1]
#=> arr[5..-1]
#=> [6, 7, 8, 9, 10, 11, 12, 13, 14]
b = a.each_slice(batch_size-fall_factor)
#=> a.each_slice(3)
#=> #<Enumerator: [6, 7, 8, 9, 10, 11, 12, 13, 14]:each_slice(3)>
We can see the elements of the enumerator b by converting it to an array:
b.to_a
#=> [[6, 7, 8], [9, 10, 11], [12, 13, 14]]
Continuing:
d = [arr[0,batch_size]]
#=> [[1, 2, 3, 4, 5]]
b.each_with_object(d) { |b,c| c << [*c.last[-fall_factor..-1], *b] }
#=> [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8], [7, 8, 9, 10, 11], [10, 11, 12, 13, 14]]
To see how the last calculation is performed, let:
e = b.each_with_object(d)
#=> #<Enumerator: #<Enumerator: [6, 7, 8, 9, 10, 11, 12, 13, 14]:
# each_slice(3)>:each_with_object([[1, 2, 3, 4, 5]])>
e.to_a
#=> [[[6, 7, 8], [[1, 2, 3, 4, 5]]],
# [[9, 10, 11], [[1, 2, 3, 4, 5]]],
# [[12, 13, 14], [[1, 2, 3, 4, 5]]]]
We can use Enumerator#next to obtain each element of e that is passed to the block, set the block variables to each of those values and perform the block calculation. The first element is passed to the block:
b, c = e.next
#=> [[6, 7, 8], [[1, 2, 3, 4, 5]]]
b #=> [6, 7, 8]
c #=> [[1, 2, 3, 4, 5]]
The block calculation is therefore:
c << [*c.last[-fall_factor..-1], *b]
#=> c << [*[[1, 2, 3, 4, 5]].last[-2..-1], *[6, 7, 8]]
# c << [*[1, 2, 3, 4, 5][-2..-1], *[6, 7, 8]]
# c << [*[4, 5], *[6, 7, 8]]
# c << [4, 5, 6, 7, 8]
c #=> [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8]]
The next element of e is now passed to the block:
b, c = e.next
#=> [[9, 10, 11], [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8]]]
b #=> [9, 10, 11]
c #=> [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8]]
The remaining calculations are performed similarly.

Based on logic shared by you, below is one possible implementation:
b = 5 # batch size
f = 2 # fall factor
indices = (0...src_arr.size).collect {|i| i * (b-f)}.reject {|i| i + f >= src_arr.size}
result = indices.each_with_object([]) do |i, obj|
obj << src_arr[i, b]
end
p result
#=> [[1, 2, 3, 4, 5], [4, 5, 6, 7, 8], [7, 8, 9, 10, 11], [10, 11, 12, 13, 14]]

Related

I tried to solve n queens problem, but my program returns ... instead of

def attack(k,x):
for i in range(0,k-1):
if x[i]==x[k] or abs(x[i]-x[k])==abs(i-k):
return 1
return 0
def nQueens(n):
x=[]
for i in range(0,n):
x.append(-1)
k=0
solution=[]
while k>=0:
x[k]=x[k]+1
while x[k]<=n-1 and attack(k,x)==1:
x[k]=x[k]+1
if x[k]<=n-1:
if k==n-1:
solution.append(x)
else:
k=k+1
x[k]=0
else:
k=k-1
return solution
n=4
print(nQueens(n))
I tried to solve n queens problem, but my program returns
[[4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4], [4, 4, 4, 4]]
instead of [[2, 4, 1, 3], [3, 1, 4, 2]]. Any suggestions where am I wrong?

dart generating all possible combinations list of lists

I have a list of lists, similar to this:
a = [ [1,2,3], [4,5,6], [7,8,9,10]]
I'd like to create all possible combinations, like this:
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]
For python, there's a library that does exactly this.
Is there a similar solution for Dart?
If not, I'd appreciate a simple code that accomplish that
One approach could be:
Iterable<List<T>> allCombinations<T>(List<List<T>> sources) sync* {
if (sources.isEmpty || sources.any((l) => l.isEmpty)) {
yield [];
return;
}
var indices = List<int>.filled(sources.length, 0);
var next = 0;
while (true) {
yield [for (var i = 0; i < indices.length; i++) sources[i][indices[i]]];
while (true) {
var nextIndex = indices[next] + 1;
if (nextIndex < sources[next].length) {
indices[next] = nextIndex;
break;
}
next += 1;
if (next == sources.length) return;
}
indices.fillRange(0, next, 0);
next = 0;
}
}
This works by effectively treating the indices as a number in variable base based on the source list lengths, then incrementing it and creating the corresponding list.
Time complexity is still 𝒪(Πi(source[i].length) * source.length).
Could not find a package which does exactly what you want, but I guess your can do something like this if you want to introduce your own method:
void main() {
print(combinations([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9, 10]
]));
// ([1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 4, 10], ..., [3, 6, 9], [3, 6, 10])
}
Iterable<List<T>> combinations<T>(
List<List<T>> lists, [
int index = 0,
List<T>? prefix,
]) sync* {
prefix ??= <T>[];
if (lists.length == index) {
yield prefix.toList();
} else {
for (final value in lists[index]) {
yield* combinations(lists, index + 1, prefix..add(value));
prefix.removeLast();
}
}
}
More efficient solution but also more risky to use since it does require the user of combinations to take care when consuming the output and make sure not to keep any instances of the inner Iterable:
void main() {
print(combinations([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9, 10]
]).map((e) => e.toList()));
// ([1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 4, 10], ..., [3, 6, 9], [3, 6, 10])
}
Iterable<Iterable<T>> combinations<T>(
List<List<T>> lists, [
int index = 0,
List<T>? prefix,
]) sync* {
prefix ??= <T>[];
if (lists.length == index) {
yield prefix;
} else {
for (final value in lists[index]) {
yield* combinations(lists, index + 1, prefix..add(value));
prefix.removeLast();
}
}
}
The problem with this solution is the risk of misuse as the following example:
final listOfCombinations = combinations([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9, 10]
]).toList();
print(listOfCombinations);
// [[], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], []]
Which should instead be:
final listOfCombinations = combinations([
[1, 2, 3],
[4, 5, 6],
[7, 8, 9, 10]
]).map((e) => e.toList()).toList();
print(listOfCombinations);
// [[1, 4, 7], [1, 4, 8], [1, 4, 9], [1, 4, 10], [1, 5, 7], [1, 5, 8], [1, 5, 9], [1, 5, 10], [1, 6, 7], [1, 6, 8], [1, 6, 9], [1, 6, 10], [2, 4, 7], [2, 4, 8], [2, 4, 9], [2, 4, 10], [2, 5, 7], [2, 5, 8], [2, 5, 9], [2, 5, 10], [2, 6, 7], [2, 6, 8], [2, 6, 9], [2, 6, 10], [3, 4, 7], [3, 4, 8], [3, 4, 9], [3, 4, 10], [3, 5, 7], [3, 5, 8], [3, 5, 9], [3, 5, 10], [3, 6, 7], [3, 6, 8], [3, 6, 9], [3, 6, 10]]
So, use the first suggested solution if you don't want the risk of this kind of issues. :)
check out this answer. working for the problem you are searching for:
https://stackoverflow.com/a/57883482/11789758

Build and order an array with the first element of other arrays

I'm trying to transform an array of 3 arrays in an array of 4 where each array is built and ordered with the first element of each other.
I have this:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
And I would like the following:
[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
Any ideas?
Use Array#transpose.
your_array.transpose
will do it.
array = [[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]
array.transpose
[[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]]
Is this what you were looking for?

Ruby "bucketize" an array

Suppose I have the following array:
a = (1..10).to_a
Is there a single in-built ruby (or rails) function that is capable or splitting the array into exactly N roughly equal parts while maintaining the order?
I'm looking for something like this:
a.bucketize(3)
=> [[1,2,3,4],[5,6,7],[8,9,10]]
a.bucketize(5)
=> [[1,2],[3,4],[5,6],[7,8],[9,10]]
Hint: each_slice doesn't do this.
Also, I know I could write this function myself and open up the Array class or Enumerable module.
Thanks.
I'd do it like this:
ary = (1..10).to_a
ary.each_slice((ary.length.to_f/3).ceil).to_a
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10]]
ary.each_slice((ary.length.to_f/5).ceil).to_a
=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10]]
It's not perfect, but it does come close:
ary = (1..9).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9]
ary.each_slice((ary.length.to_f/2).ceil).to_a
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9]]
ary.each_slice((ary.length.to_f/3).ceil).to_a
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
ary.each_slice((ary.length.to_f/4).ceil).to_a
=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
This kind of task is best tackled using a functional approach. Here's a tail-recursive functional implementation (except for the unavoidable << to accumulate efficiently on arrays):
class Array
def bucketize(n, index = 0, acc = [])
return acc if n <= 0 || size <= index
n0 = ((size - index).to_f / n).ceil
bucketize(n - 1, index + n0, acc << self[index, n0])
end
end
(1..9).to_a.bucketize(3)
#=> [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
(1..10).to_a.bucketize(3)
#=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
(1..11).to_a.bucketize(3)
#=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]
Here's what I ended up doing:
class Array
def bucketize(n)
return [] if (buckets = n.to_i) <= 0
j = length / buckets.to_f
result = each_with_index.chunk { |_, i| (i / j).floor }.map { |_, v| v.map(&:first) }
result << [] until result.length == buckets
result
end
end
Examples:
a = (1..10).to_a
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a.bucketize(1)
=> [[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]]
a.bucketize(2)
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]
a.bucketize(3)
=> [[1, 2, 3, 4], [5, 6, 7], [8, 9, 10]]
a.bucketize(4)
=> [[1, 2, 3], [4, 5], [6, 7, 8], [9, 10]]
...
a.bucketize(9)
=> [[1, 2], [3], [4], [5], [6], [7], [8], [9], [10]]
...
a.bucketize(11)
=> [[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], []]

ruby array iteration

I have four arrays(named array1,2,3,4) each with 8 objects and want to sort them into 8 empty arrays that will consist of 4 objects each, i.e place each object from array 1 into an empty array.
?? << array1.shift until array.empty?
I'm not sure how to iterate over the 8 empty arrays so that each of them recieves an object from array1
e.g
array1 = clubs1-8
array2 = spades1-8
array3 = hearts1-8
array4 = diamonds1-8
8 empty arrays or players, each player is dealt a card from array1,then 1 card from array2 etc.
Thanks for the answers but I wanted to add the objects iteratively so I could add conditions based on what objects had already been added to each array
e.g
distribute array1 among 8 empty arrays
distribute array2 among the 8 arrays but check before that no array contains the same card number (it can't have both the 2 of hearts and the 2 of diamonds)
Did you mean something like this?
require "matrix"
a1 = (0..7).to_a
a2 = (8..15).to_a
a3 = (16..23).to_a
a4 = (24..31).to_a
Matrix[a1, a2, a3, a4].transpose.to_a #=> [[0, 8, 16, 24], [1, 9, 17, 25], [2, 10, 18, 26], [3, 11, 19, 27], [4, 12, 20, 28], [5, 13, 21, 29], [6, 14, 22, 30], [7, 15, 23, 31]]
Added:
In fact it is even more trivial:
a1.zip(a2, a3, a4) #=> [[0, 8, 16, 24], [1, 9, 17, 25], [2, 10, 18, 26], [3, 11, 19, 27], [4, 12, 20, 28], [5, 13, 21, 29], [6, 14, 22, 30], [7, 15, 23, 31]]
Iteration is not the only way. Try this (assuming a1..a8 are your 8 empty arrays):
a1, a2, a3, a4, a5, a6, a7, a8 = array1.zip(array2, array3, array4)
irb(main):001:0> ar1 = [1,2,3,4,5,6,7,8]
=> [1, 2, 3, 4, 5, 6, 7, 8]
irb(main):002:0> ar2 = [2,3,4,1,2,3,2,1]
=> [2, 3, 4, 1, 2, 3, 2, 1]
irb(main):003:0> ar3 = [4,3,5,6,3,3,4,5]
=> [4, 3, 5, 6, 3, 3, 4, 5]
irb(main):004:0> ar4 = [5,2,5,6,7,2,2,5]
=> [5, 2, 5, 6, 7, 2, 2, 5]
irb(main):005:0> ar1.zip(ar2,ar3,ar4)
=> [[1, 2, 4, 5], [2, 3, 3, 2], [3, 4, 5, 5], [4, 1, 6, 6], [5, 2, 3, 7], [6, 3, 3, 2], [7, 2, 4, 2], [8, 1, 5, 5]]

Categories

Resources