I'm having trouble explaining what I am looking for so I will provide an example, let's say I have this array:
[
[1, 2],
[1, 3],
[1, 4],
[2, 3],
[2, 4],
[3, 4]
]
rather than sorting it by the first column, I would like it to cycle through the first column, so instead of 1, 1, 1, 2, 2, 3 it would do: 1, 2, 3, 1, 2, 1
resulting in:
[
[1, 2],
[2, 3],
[3, 4],
[1, 3],
[2, 4],
[1, 4]
]
Even better would be if it could cycle through both columns to prevent two numbers in a row as much as possible, the ideal solution would sort the original array as:
[
[1, 2],
[3, 4],
[1, 3],
[2, 4],
[1, 4],
[2, 3]
]
Leading to the maximum spacing between repeating numbers for each inner array (both columns being taken into account).
I hope I have provided sufficient information, and I will greatly appreciate any advise, I am fairly clueless so far, searching has yeilded me nothing.
I will only address the first part of your question as I don't understand what you mean by "Even better would be if it could cycle through both columns to prevent two numbers in a row as much as possible...". The clause "as much as possible" is especially troublesome, as it refers to an unspecified criterion.
Let arr be your array. The elements are sorted in your example, but if they were not, the first step would be:
arr.sort!
See Array#sort! and Array#<=> for an explanation of how Ruby sorts arrays whose elements are arrays.
There are many ways to obtain the desired ordering. Here is one that uses Enumerable#chunk:
arr.chunk(&:first).flat_map {|_,a| a.map.with_index {|i,b| [b,i]}}.sort.map(&:last)
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]
The steps are as follows:
e = arr.chunk(&:first)
#=> #<Enumerator: #<Enumerator::Generator:0x007fa01a8141d0>:each>
We can see the elements of this enumerator, which are passed to the block by Enumerator#each (which calls Array#each), by converting it to an array:
e.to_a
#=> [[1, [[1, 2], [1, 3], [1, 4]]], [2, [[2, 3], [2, 4]]], [3, [[3, 4]]]]
Continuing:
f = e.flat_map { |_,a| a.map.with_index { |i,b| [b,i] } }
#=> [[0, [1, 2]], [1, [1, 3]], [2, [1, 4]], [0, [2, 3]], [1, [2, 4]], [0, [3, 4]]]
g = f.sort
#=> [[0, 1, 2], [0, 2, 3], [0, 3, 4], [1, 1, 3], [1, 2, 4], [2, 1, 4]]
g.map(&:last)
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]
Let's look more closely at the calculation of f:
h = e.flat_map
#=> #<Enumerator: #<Enumerator: #<Enumerator::Generator:0x007fa01a8141d0>:each>:flat_map>
h.to_a
#=> [[1, [[1, 2], [1, 3], [1, 4]]], [2, [[2, 3], [2, 4]]], [3, [[3, 4]]]]
You can think of h as a "compound" enumerator.
The first value of h, [1, [[1, 2], [1, 3], [1, 4]]], is passed to the block and captured by the block variables using parallel (or multiple) assignment:
i, a = h.next
#=> [1, [[1, 2], [1, 3], [1, 4]]]
i #=> 1
a #=> [[1, 2], [1, 3], [1, 4]]
As i is not used in the block calculation, it is customary to replace that block variable with the local variable _.
We can now perform the block calculation:
a.map.with_index { |i,b| [b,i] }
#=> [[0, [1, 2]], [1, [1, 3]], [2, [1, 4]]]
The remaining calculations are performed similarly.
you could try this
def func ary
ret = []
# group by first ones, and each sort by second ones
a = ary.group_by{|i| i[0]}.map{|_,i| i.sort_by{|j| j[1]}}
# add to ret
(0...a.map{|i| i.size}.max).map{
a.map{|i| ret << i.shift}
}
ret.compact
end
a = [[1, 2],[1, 3],[1, 4],[2, 3],[2, 4],[3, 4]]
p func(a)
#=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]
Assuming the initial array is sorted by the first element:
arr =
[
[1, 2],
[1, 3],
[1, 4],
[2, 3],
[2, 4],
[3, 4],
]
res = []
arr_dup = arr.dup
remaining_values = arr_dup.map { |el| el[0] }
current_value = remaining_values.first
loop do
arr_dup.each_with_index do |el, index|
if el[0] >= current_value
res << el
current_value = remaining_values.select { |v| v > el[0] }.first || remaining_values.first
remaining_values.delete_at(remaining_values.index(current_value))
arr_dup.delete_at(index)
break
end
end
break if remaining_values.empty?
end
p arr #=> [[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
p res #=> [[1, 2], [2, 3], [3, 4], [1, 3], [2, 4], [1, 4]]
Few tests:
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [5, 1], [20, 2]] =>
[[1, 2], [2, 3], [3, 4], [5, 1], [20, 2], [1, 3], [2, 4], [1, 4]]
[[1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4], [5, 1], [5, 2], [20, 2]] =>
[[1, 2], [2, 3], [3, 4], [5, 1], [20, 2], [1, 3], [2, 4], [5, 2], [1, 4]]
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I have such kind array and I want to remove duplicate values in swift 3.0
[[2, 2, 2], [2, 2, 2], [2, 2, 1], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2,
2, 1], [2, 2, 2], [2, 2, 2], [2, 1, 1], [2, 1, 2], [2, 1, 2], [2, 2,
2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [2, 2, 1], [2, 2, 2], [2, 2, 2],
[2, 1, 1], [2, 1, 2], [2, 1, 2], [2, 2, 2], [2, 2, 2], [2, 2, 2], [1,
1, 1], [1, 1, 2], [1, 1, 2], [1, 2, 2], [1, 2, 2], [1, 2, 2], [2, 2,
2], [2, 2, 2], [2, 2, 2], [2, 2, 2]]
so what code i have to write for this.
Use this code below to filter duplicate arrays and will get in ordered array
let filteredArr = Array(NSOrderedSet(array: arr))
[ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ]
[ 'a', 'b', 'b', 'z' ] & [ 'a', 'b', 'c' ] #=> [ 'a', 'b' ]
I need the intersection of each array with all other arrays within an array.
So the array could look like ->
a = [[1, 2, 3], [3, 4, 5], [4, 5, 6]]
The result should look like ->
a = [[3],[3,4,5][4,5]]
Any suggestions?
Look into the combination method.
a = [[1, 2, 3], [3, 4, 5], [4, 5, 6],[1,"a","b"]]
p a.combination(2).map{|x,y| x & y } #=> [[3], [], [1], [4, 5], [], []]
And if you do not want the empty arrays in there:
p a.combination(2).map{|x,y| x & y }.reject(&:empty?) #=> [[3], [1], [4, 5]]
Edit: After seeing some examples what OP actually want here is how I would achieve the desired result:
original = [[1, 2, 3], [3, 4, 5], [4, 5, 6]]
def intersect_with_rest(array)
array.size.times.map do
first, *rest = array
array.rotate!
first & rest.flatten
end
end
p intersect_with_rest(original) #=> [[3], [3, 4, 5], [4, 5]]
p original #=> [[1, 2, 3], [3, 4, 5], [4, 5, 6]]
Or:
original = [[1, 2, 3], [3, 4, 5], [4, 5, 6]]
result = original.map.with_index do |x,i|
x & (original[0...i]+original[1+i..-1]).flatten
end
p result #=> [[3], [3, 4, 5], [4, 5]]
Yeah, finally I found a solution. Maybe there is a simpler way, but that works for me now..
c = [[1,2,3],[3,4,5],[4,5,6]]
results = [];c.length.times.each {|e| results.push c.rotate(e).combination(2).map {|x, y| x & y}}
results.map{|x, y| y + x}
=> [[3], [3, 4, 5], [4, 5]]
Thanks to #hirolau for the hint. Best regards
- #nutritions = Hash.new
- #ingredients.each_with_index do |ingredient,i|
- ingredient.nutritions.each_with_index do |nutrition, j|
- #nutritions[[i,j]] = nutrition.amount
- #nutritions.each do |nutrition|
= nutrition
gives me two "blocks" with amounts (example has 2 ingredients, with 4 nutritions):
[[ingredient, nutrition], amount]
[[0, 0], 900.0]
[[0, 1], 3769.0]
[[0, 2], 0.0]
[[0, 3], 100.0]
[[1, 0], 258.0]
[[1, 1], 1080.0]
[[1, 2], 64.0]
[[1, 3], 0.0]
I'm searching for a way to add up each hash value (amount),
and store it in another key behind, like
[[2, 0], 1158.0]
[[2, 1], 4849.0]
[[2, 2], 64.0]
[[2, 3], 100.0]
So. If there're 5 ingredients, store the sum of them in the 6th "block"
Solution:
(Thx to Smathy!)
[[0, 0], 900.0]
[[3, 0], 1507.0]
[[0, 1], 3769.0]
[[3, 1], 6310.0]
[[0, 2], 0.0]
[[3, 2], 136.0]
[[0, 3], 100.0]
[[3, 3], 101.0]
[[1, 0], 258.0]
[[1, 1], 1080.0]
[[1, 2], 64.0]
[[1, 3], 0.0]
[[2, 0], 349.0]
[[2, 1], 1461.0]
[[2, 2], 72.0]
[[2, 3], 1.0]
To give you literally what you're asking for:
- #nutritions = Hash.new
- end_of_list = #ingredients.length
- #ingredients.each_with_index do |ingredient,i|
- ingredient.nutritions.each_with_index do |nutrition, j|
- #nutritions[[i,j]] = nutrition.amount
- #nutritions[[end_of_list,j]] ||= 0
- #nutritions[[end_of_list,j]] += nutrition.amount
There's probably a much nicer way to accomplish your real goal, but without knowing what you're actually trying to accomplish it's impossible to guess the best way.
arr = [
[0, "Moving Companies", 10],
[0, "ab-thera-sensa", 5],
[0, "belt-center", 16],
[0, "isabel", 3],
[0, "kreatio", 2],
[0, "service1", 7],
[0, "sorbion-sachet-multi-star", 6],
[0, "sss", 15],
[0, "telecom-service-industry", 14],
[1, " AbsoPad", 13],
[1, "telecom-service", 8],
[2, "cutisorb-ultra", 12],
[2, "sorbion-contact", 11],
[2, "sorbion-sachet-multi-star", 9]
]
Suppose this is my array, now I want to sort it on the basis of the first element in descending order. I can do a arr.sort.reverse but the problem starts now
I get the array as :
[
[2, "sorbion-sachet-multi-star", 9],
[2, "sorbion-contact", 11],
[2, "cutisorb-ultra", 12],
[1, "telecom-service", 8],
[1, " AbsoPad", 13],
[0, "telecom-service-industry", 14],
[0, "sss", 15], [0, "sorbion-sachet-multi-star", 6],
[0, "service1", 7],
[0, "kreatio", 2],
[0, "isabel", 3],
[0, "belt-center", 16],
[0, "ab-thera-sensa", 5],
[0, "Moving Companies", 10]
]
Now the array should be sorted on the basis of the second element in ascending order.
How can that be achieved?
The result should look like :
[
[2, "cutisorb-ultra", 12],
[2, "sorbion-contact", 11],
[2, "sorbion-sachet-multi-star", 9],
[1,.......]
]
Customize the sorting with a block. First do a descending sort by the first element (0). If they are equal do instead an ascending sort by the second element (1):
arr.sort! do |a, b|
result = b[0] <=> a[0]
result = a[1] <=> b[1] if result == 0
result
end
How about this?
arr.sort { |i,j| [j[0],j[2]] <=> [i[0],i[2]] }
Outputs:
=> [[2, "cutisorb-ultra", 12],
[2, "sorbion-contact", 11],
[2, "sorbion-sachet-multi-star", 9],
[1, " AbsoPad", 13],
[1, "telecom-service", 8],
[0, "belt-center", 16],
[0, "sss", 15],
[0, "telecom-service-industry", 14],
[0, "Moving Companies", 10],
[0, "service1", 7],
[0, "sorbion-sachet-multi-star", 6],
[0, "ab-thera-sensa", 5],
[0, "isabel", 3],
[0, "kreatio", 2]]
please try:
arr.sort_by{|x|[-x[0],-x[2]]}
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], []]