Ruby - pushing values from an array combination to a new array - ruby

I am trying to print all the different sums of all combinations in this array [1,2,3]. I want to first push every sum result to a new array b, then print them using b.uniq so that non of the sum results are repeated.
However, with the code I have, the 3 repeats itself, and I think it is because of the way it is pushed into the array b.
Is there a better way of doing this?
a = [1,2,3]
b = []
b.push a
b.push a.combination(2).collect {|a,b| (a+b)}
b.push a.combination(3).collect {|a,b,c| (a+b+c)}
puts b.uniq
p b #[[1, 2, 3], [3, 4, 5], [6]]
Can someone please help me with this? I am still new in ruby.

Because an Array of arbitrary length can be summed using inject(:+), we can create a more general solution by iterating over the range 1..n, where n is the length of the Array.
(1..(a.size)).flat_map do |n|
a.combination(n).map { |c| c.inject(&:+) }
end.uniq
#=> [1, 2, 3, 4, 5, 6]
By using flat_map, we can avoid getting the nested Array result, and can call uniq directly on it. Another option to ensure uniqueness would be to pass the result to a Set, for which Ruby guarantees uniqueness internally.
require "set"
sums = (1..(a.size)).flat_map do |n|
a.combination(n).map { |c| c.inject(&:+) }
end
Set.new(sums)
#=> #<Set: {1, 2, 3, 4, 5, 6}>
This will work for an any Array, as long as all elements are Fixnum.

If all you want is an array of the possible sums, flatten the array before getting the unique values.
puts b.flatten.uniq
What is happening is uniq is running over a multi-dimensional array. This causes it to look for duplicate arrays in your array. You'll need the array to be flattened first.

Related

How to remove duplicate contiguous elements in an array?

Given an array such as
arr = [1,1,1,2,2,3,4,1,2]
I wish to replace each contiguous string of equal elements with a single instance of that element. Here the result would be
[1,2,3,4,1,2]
The three 1s are replaced by a single 1 and the two 2's are replaced by a single 2.
How can I do that for an arbitrary array of Ruby objects?
I know you can do it with chunk_while and map, but there might be other ways:
[1,1,1,2,2,3,4,1,2].chunk_while { |e, f| e == f }.map(&:first)
# [1, 2, 3, 4, 1, 2]
With chunk_while you split the array by chunks whenever the block is evaluated to true, for that the block yields two variables, the "element before" and the "element after", that's to say, for every iteration you're going to get this:
[1, 1]
[1, 1]
[1, 2]
[2, 2]
[2, 3]
[3, 4]
[4, 1]
[1, 2]
After applying the logic in the proc, it'll chunk the receiver whenever the first and second yielded elements are equal, and you get:
[[1, 1, 1], [2, 2], [3], [4], [1], [2]]
After that you can map that result to get only one element from each array - there are many ways, but first is enough.
The chunk_while proc can also be shortened to (&:==), leaving as [1,1,1,2,2,3,4,1,2].chunk_while(&:==).map(&:first).
Similarly and just out of curiosity, you can use slice_when and last to save 2 characters: [1,1,1,2,2,3,4,1,2].slice_when(&:!=).map(&:last).
You can use recursive functions to solve this type problems.
I tried different tests. It works.
mylist = [1,1,1,2,2,3,4,1,2] #Output:[1,2,3,4,1,2]
mylist2 = [1,1,1,1,1,1,2,2,2,2,3,3,5,5,5,4,1,2] # Output:[1,2,3,5,4,1,2]
mylist3 = [-1,-1,-2,3,5,5,5,4,3,8,8,8,9,6,0,0,6,5] # Output: [-1,-2,3,5,4,3,8,9,6,0,6,5]
def myfunc(mylist)
mylist.each_with_index do |val, index|
if val == mylist[index+1]
mylist.delete_at(index+1)
myfunc(mylist) # here we call same function again
end
end
return mylist
end
print myfunc(mylist)
puts
print myfunc(mylist2)
puts
print myfunc(mylist3)
arr = [1,1,1,2,2,3,4,1,2]
arr.each do |i|
(0..arr.length()).each do |j|
if arr[j] == arr[j+1]
arr.delete_at(j)
break
end
end
end
print arr
What is happening here is the entire list is being traversed; matching consecutive elements in each iteration.
Everytime a match is found, delete it and move on to the next iteration (break).
In effect, you will be changing the length of the array in each iteration. hence the break to avoid index errors.
The nested looping is added to handle any no. of consecutive duplicates.

How to achieve all elements swapped in an array

I have an ordered array which contain 1 to 1000000 elements.
I want to achieve an array such that the elements in the array are swapped with its next element.For instance if we assume the array elements are
[1,2,3,4,5,6]
I want to return an array with elements as
[2,1,4,3,6,5]
How do I achieve this in ruby for 100000 such elements? Can anyone guide me?
a = [1,2,3,4,5,6]
a.each_slice(2).map{|inner_a| inner_a.reverse}.flatten
# => [2, 1, 4, 3, 6, 5]
Description:
a.each_slice(2)returns an enumerator (#<Enumerator: [1, 2, 3, 4, 5, 6]:each_slice(2)>) with two element couples from your array. To see try a.each_slice(2).to_a. This returns [[1, 2], [3, 4], [5, 6]] with I only have to flatten for your expected result.
See also the first comment if you prefer a shorter notation of it.
Assuming you want to use a minimum amount of memory (since you chose a large array), and assuming the result is to be a mutated array (i.e. not a new array, but a change to the existing array) and finally assuming a is always an even number of elements...
a.each_index{|x| a[x], a[x+1] = a[x+1], a[x] if x.even?}
Possibly more performant...
(0...a.size).step(2) {|x| a[x], a[x+1] = a[x+1], a[x]}
You can try this.
arr = (1..100000).to_a
arr.each_with_index.each_slice(2){|(_,i), (_,j)| arr[i], arr[j] = arr[j], arr[i]}

Adding unparallel elements between two arrays

I have a pair of arrays,
array_1 = [1,2,3,4,5]
array_2 = [10,9,8,7,6]
and I'm trying to subtract the nth element of one array from the (n-1)-th element of the second array, starting with the n-th element, yielding an array of:
[9-1, 8-2, 7-3, 6-4] = [8, 6, 4, 2]
I wrote it in a procedural fashion:
array_1.pop
array_2.shift
[array_2,array_1].transpose.map { |a,b| a-b }
but I do not wish to alter the arrays. Is there a method or another way to go about this?
Another way:
enum1 = array_1.to_enum
enum2 = array_2.to_enum
enum2.next
arr = []
loop do
arr << enum2.next - enum1.next
end
arr
#=> [8, 6, 4, 2]
Use the non-destructive drop for the receiver, and zip, which will stop when the receiver runs out of an element even if the argument has more.
array_2.drop(1).zip(array_1).map{|a, b| a - b}
I think you may be overthinking it a bit; as long as both arrays are the same length, you can just iterate over the indices you care about, and reference the other array by index - offset.
array_1 = [1,2,3,4,5]
array_2 = [10,9,8,7,6]
n = 1
(n...array_1.length).map {|i| array_2[i] - array_1[i - 1] }
You can set n to whatever number you like and compute from that point onwards, so even if the arrays were tremendously large, you don't have to generate any intermediate arrays, and you don't have to perform any unnecessary work.

Indexing an array with duplicate elements before and after sorting

This is the basic problem: I have an array of integers with possibly duplicate elements. I need to know the indices of each element, but when I sort the array, whenever I select an element from the new array, I want to be able to reference the same element from the original array.
I am looking for a solution to the problem, or maybe a solution to the approach I am taking.
Here is an array
a = [1, 2, 3, 4, 3, 5, 2]
There are two 2's and two 3's, but if I'm working with the first 2 (from the left), I want to work with index 1, and if I'm working with the second 2, I want to be working with index 6. So I use a helper array to allow me to do this:
helper = [0, 1, 2, 3, 4, 5, 6]
Which I will iterate over and use to access each element from a.
I could have accomplished this with each_with_index, but the problem begins when I sort the array.
Now I have a sort order
sort_order = [2, 4, 1, 5, 3]
I use sort_by to sort a according to sort_order, to produce
sorted_a = [2, 2, 4, 1, 5, 3, 3]
You may assume all elements in the input exist in sort_order to avoid sort_by exceptions.
Now the problem is that my helper array should be updated to match the new positions. Each element should be sorted the same way as a was sorted, because it is unclear whether the first 2 in the new array was at index 1 or at index 6 of the original array.
So my new helper array might look like
new_helper = [1, 6, 3, 0, 5, 2, 4]
So if I were to go with this approach, how would I produce the new_helper array, given the original array and the sort order?
Maybe there is a better way to do this?
I would suggest first zip the original array with the helper array, sort the zipped array according the component coming from the original array, then unzip them (this method does not exist unfortunately, but you can do transpose). Or you can implement your own sorting logic as pointed out by Hunter.
Make a list of pairs of the original data and that data's index. Like this:
a = [(1, 0), (2, 1), (3, 2), (4, 3), (3, 4), (5, 5), (2,6)]
Sort that list (lexicographically, or just ignore the second part of the pair except to carry it along). The second item in every pair tells you where the element was in the original array.
You need to swap the values in the helper array when you swap then in your main array.
loop do
swapped = false
0.upto(list.size-2) do |i|
if list[i] > list[i+1]
list[i], list[i+1] = list[i+1], list[i] # swap values
helper[i], helper[i+1] = helper[i+1], helper[i]; #swap helper values
swapped = true
end
end
break unless swapped
end
Example
irb(main):001:0> def parallel_sort(list, helper)
irb(main):002:1> loop do
irb(main):003:2* swapped = false
irb(main):004:2> 0.upto(list.size-2) do |i|
irb(main):005:3* if list[i] > list[i+1]
irb(main):006:4> list[i], list[i+1] = list[i+1], list[i] # swap values
irb(main):007:4> helper[i], helper[i+1] = helper[i+1], helper[i]; #swap helper values
irb(main):008:4* swapped = true
irb(main):009:4> end
irb(main):010:3> end
irb(main):011:2> break unless swapped
irb(main):012:2> end
irb(main):013:1> return [list, helper]
irb(main):014:1> end
=> nil
irb(main):015:0> a = [3,2,1]
=> [3, 2, 1]
irb(main):016:0> b = ["three","two","one"]
=> ["three", "two", "one"]
irb(main):017:0> parallel_sort(a,b)
=> [[1, 2, 3], ["one", "two", "three"]]
irb(main):018:0>
Sorting inside a loop is rarely a good idea.... If you are doing so, you might be better off with a treap (fast on average but infrequently an operation will take a while) or red-black tree (relatively slow, but gives pretty consistent operation times). These are rather like hash tables, except they're not as fast, and they keep elements stored in order using trees.
Either way, why not use a class that saves both the value to sort by, and the helper value? Then they're always together, and you don't need a custom sorting algorithm.
Since you have sort_order, your array is already kind of sorted, so we should use this fact as an advantage. I came up with this simple solution:
a = [1, 2, 3, 4, 3, 5, 2]
sort_order = [2, 4, 1, 5, 3]
# Save indices
indices = Hash.new { |hash, key| hash[key] = [] }
a.each_with_index { |elem, index| indices[elem] << index }
# Sort the array by placing elements into "right" positions
sorted = []
helper = []
sort_order.each do |elem|
indices[elem].each do |index|
sorted << elem
helper << index
end
end
p sorted
p helper
The algorithm is based on idea of Counting sort, I slightly modified it to save indices.

Difference Between map and each [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Ruby - What is the difference between map, each and collect?
I have looked in Ruby-Doc also but i cant understand the difference between
map
each
iterators.It would be great if you could give an example and explain.
each simply iterates over the given enumerable, running the block for each value. It discards the return value of the block, and each simply returns the original object it was called on:
[1, 2, 3].each do |x|
x + 1
end # => [1, 2, 3]
This is simply a nicer, more universal way of doing a traditional iterating for loop, and each is much preferred over for loops in Ruby (in fact, I don't think I've ever used a for loop in Ruby).
map, however, iterates over each element, using the return value of the block to populate a new array at each respective index and return that new array:
[1, 2, 3].map do |x|
x + 1
end # => [2, 3, 4]
So it “maps” each element to a new one using the block given, hence the name “map”. Note that neither each nor map themselves modify the original collection. This is a concise, functional alternative to creating an array and pushing to it in an iterative loop.
each returns the original object. It's used to run an operation using each element of an array without collecting any of the results. For example, if you want to print a list of numbers, you might do something like this:
arr = [1, 2, 3, 4]
arr.each { |n| puts n }
Now, that puts method above actually returns nil. Some people don't know that, but it doesn't matter much anyway; there's no real reason to collect that value (if you wanted to convert arr to strings, you should be using arr.map(&:to_s) or arr.map { |n| n.to_s }.
map returns the results of the block you pass to it. It's a great way to run an operation on each element in an array and retrieve the results. If you wanted to multiple every element of an array by 2, this is the natural choice. As a bonus, you can modify the original object using map!. For example:
arr = [1, 2, 3, 4]
arr.map! { |n| n * 2}
# => [2, 4, 6, 8]

Resources