Calculate differences between array elements - ruby-on-rails

Given a sorted array of n integers, like the following:
ary = [3, 5, 6, 9, 14]
I need to calculate the difference between each element and the next element in the array. Using the example above, I would end up with:
[2, 1, 3, 5]
The beginning array may have 0, 1 or many elements in it, and the numbers I'll be handling will be much larger (I'll be using epoch timestamps). I've tried the following:
times = #messages.map{|m| m.created_at.to_i}
left = times[1..times.length-1]
right = times[0..times.length-2]
differences = left.zip(right).map { |x| x[0]-x[1]}
But my solution above is both not optimal, and not ideal. Can anyone give me a hand?

>> ary = [3, 5, 6, 9, 14] #=> [3, 5, 6, 9, 14]
>> ary.each_cons(2).map { |a,b| b-a } #=> [2, 1, 3, 5]
Edit:
Replaced inject with map.

Similar but more concise:
[3, 5, 6, 9, 14].each_cons(2).collect { |a,b| b-a }

An alternative:
a.map.with_index{ |v,i| (a[i+1] || 0) - v }[0..-2]
Does not work in Ruby 1.8 where map requires a block instead of returning an Enumerator.

Related

How to remove array elements and append it to the front of the array in ruby without using any inbuilt methods?

I have an array say [1,2,3,4,5,6,7,8]. I need to take an input from the user and remove the last input number of array elements and append it to the front of the array. This is what I have achieved
def test(number, array)
b = array - array[0...(array.length-1) - number]
array = array.unshift(b).flatten.uniq
return array
end
number = gets.chomp_to_i
array = [1,2,3,4,5,7,8,9]
now passing the argument to test gives me the result. However, there are two problems here. first is I want to find a way to do this append on the front without any inbuilt method.(i.e not using unshift).Second, I am using Uniq here, which is wrong since the original array values may repeat. So how do I still ensure to get the correct output? Can some one give me a better solution to this.
The standard way is:
[1, 2, 3, 4, 5, 7, 8, 9].rotate(-3) #=> [7, 8, 9, 1, 2, 3, 4, 5]
Based on the link I supplied in the comments, I threw this together using the answer to that question.
def test(number, array)
reverse_array(array, 0, array.length - 1)
reverse_array(array, 0, number - 1)
reverse_array(array, number, array.length - 1)
array
end
def reverse_array(array, low, high)
while low < high
array[low], array[high] = array[high], array[low]
low += 1
high -= 1
end
end
and then the tests
array = [1,2,3,4,5,7,8,9]
test(2, array)
#=> [8, 9, 1, 2, 3, 4, 5, 7]
array = [3, 4, 5, 2, 3, 1, 4]
test(2, array)
#=> [1, 4, 3, 4, 5, 2, 3]
Which I believe is what you're wanting, and I feel sufficiently avoids ruby built-ins (no matter what way you look at it, you're going to need to get the value at an index and set a value at an index to do this in place)
I want to find a way to do this append on the front without any inbuilt method
You can decompose an array during assignment:
array = [1, 2, 3, 4, 5, 6, 7, 8]
*remaining, last = array
remaining #=> [1, 2, 3, 4, 5, 6, 7]
last #=> 8
The splat operator (*) gathers any remaining elements. The last element will be assigned to last, the remaining elements (all but the last element) are assigned to remaining (as a new array).
Likewise, you can implicitly create an array during assignment:
array = last, *remaining
#=> [8, 1, 2, 3, 4, 5, 6, 7]
Here, the splat operator unpacks the array, so you don't get [8, [1, 2, 3, 4, 5, 6, 7]]
The above moves the last element to the front. To rotate an array n times this way, use a loop:
array = [1, 2, 3, 4, 5, 6, 7, 8]
n = 3
n.times do
*remaining, last = array
array = last, *remaining
end
array
#=> [6, 7, 8, 1, 2, 3, 4, 5]
Aside from times, no methods were called explicitly.
You could create a new Array with the elements at the correct position thanks to modulo:
array = %w[a b c d e f g h i]
shift = 3
n = array.size
p Array.new(n) { |i| array[(i - shift) % n] }
# ["g", "h", "i", "a", "b", "c", "d", "e", "f"]
Array.new() is a builtin method though ;)

Remove redundant or duplicate tuples in Ruby array

Imagine the following Ruby array:
[9, 9, 5, 5, 5, 2, 9, 9]
What's the easiest way of removing redundant tuples, producing an output like the following:
[9, 5, 2, 9]
uniq is not correct because it's examining the entire array. The ordering of the input is important and must be kept. Is there a straightforward approach to this?
Thanks!
I'd do using Enumerable#chunk
2.0.0-p0 :001 > a = [9, 9, 5, 5, 5, 2, 9, 9]
=> [9, 9, 5, 5, 5, 2, 9, 9]
2.0.0-p0 :002 > a.chunk { |e| e }.map(&:first)
=> [9, 5, 2, 9]
I would do it like
b = [];
a.each { |n| b << n if b.last != n }
and b is the result
only one array scan is needed
I like Arup's answer best, but in case you want a method that is compatible with versions that don't have chunk you can do
a = [9, 9, 5, 5, 5, 2, 9, 9]
a.inject([a[0]]) { |b,c| b.last == c ? b : b << c }
# => [9, 5, 2, 9]
This is my version:
a.each_with_object([]) { |el, arr| arr << el if arr.last != el }
#=> [9, 5, 2, 9]
For those who land on this question looking to remove "redundant" values, the OP is trying to remove "repeated consecutive" values, not "redundant" or "duplicate" values and used the wrong word. They are different situations.
For clarification, removing redundant or duplicate values would be:
asdf = [9, 9, 5, 5, 5, 2, 9, 9]
asdf.uniq # => [9, 5, 2]
Or:
asdf & asdf # => [9, 5, 2]
Or:
require 'set'
asdf.to_set.to_a # => [9, 5, 2]
And, yes, I know the OP is asking for a different result. This is to show the answer for the question that was asked, NOT what what would meet the desired output. For that see the selected answer.
This is to show how you could use an enumerator directly, with the methods Enumerator#next and Enumerator#peek.
def purge_conseq_dups(arr)
return arr if arr.empty?
enum = arr.to_enum
a = []
loop do
e = enum.next
a << e unless e == enum.peek
end
a << arr.last
end
asdf = [9, 9, 5, 5, 5, 2, 9, 9]
purge_conseq_dups(asdf) #=> [9, 5, 2, 9]
When e is the last element of the enumerator enum, enum.peek raises a StopInteration exception which is rescued by Kernel#loop, which responds by breaking out of the loop. At that point all that remains is to append the last element of arr to a.
We could write a << e rather than a << arr.last, provided we initialize e prior to the loop (e.g., e = nil) so that the variable will be in scope in the last line.

How do I add an array of records at the beginning of another array of records?

I have two arrays of database records.
I'd like to add the second one to the beginning of the first.
I looked into insert, at a specific indexx, but it would result in inserting the second array inside the first one.
It might not be that hard, but thanks in advance for any help.
How is this Array#+ ?
array2 = [1,2,3]
array1 = [11,21]
array2 + array1
# => [1, 2, 3, 11, 21]
Ruby's splat to the rescue:
a = [1, 2, 3]
b = [4, 5, 6]
a.unshift(*b)
a #=> [4, 5, 6, 1, 2, 3]

Dividing elements of a ruby array into an exact number of (nearly) equal-sized sub-arrays [duplicate]

This question already has answers here:
How to chunk an array in Ruby
(2 answers)
Closed 4 years ago.
I need a way to split an array in to an exact number of smaller arrays of roughly-equal size. Anyone have any method of doing this?
For instance
a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
groups = a.method_i_need(3)
groups.inspect
=> [[1,2,3,4,5], [6,7,8,9], [10,11,12,13]]
Note that this is an entirely separate problem from dividing an array into chunks, because a.each_slice(3).to_a would produce 5 groups (not 3, like we desire) and the final group may be a completely different size than the others:
[[1,2,3], [4,5,6], [7,8,9], [10,11,12], [13]] # this is NOT desired here.
In this problem, the desired number of chunks is specified in advance, and the sizes of each chunk will differ by 1 at most.
You're looking for Enumerable#each_slice
a = [0, 1, 2, 3, 4, 5, 6, 7]
a.each_slice(3) # => #<Enumerator: [0, 1, 2, 3, 4, 5, 6, 7]:each_slice(3)>
a.each_slice(3).to_a # => [[0, 1, 2], [3, 4, 5], [6, 7]]
Perhaps I'm misreading the question since the other answer is already accepted, but it sounded like you wanted to split the array in to 3 equal groups, regardless of the size of each group, rather than split it into N groups of 3 as the previous answers do. If that's what you're looking for, Rails (ActiveSupport) also has a method called in_groups:
a = [0,1,2,3,4,5,6]
a.in_groups(2) # => [[0,1,2,3],[4,5,6,nil]]
a.in_groups(3, false) # => [[0,1,2],[3,4], [5,6]]
I don't think there is a ruby equivalent, however, you can get roughly the same results by adding this simple method:
class Array; def in_groups(num_groups)
return [] if num_groups == 0
slice_size = (self.size/Float(num_groups)).ceil
groups = self.each_slice(slice_size).to_a
end; end
a.in_groups(3) # => [[0,1,2], [3,4,5], [6]]
The only difference (as you can see) is that this won't spread the "empty space" across all the groups; every group but the last is equal in size, and the last group always holds the remainder plus all the "empty space".
Update:
As #rimsky astutely pointed out, the above method will not always result in the correct number of groups (sometimes it will create multiple "empty groups" at the end, and leave them out). Here's an updated version, pared down from ActiveSupport's definition which spreads the extras out to fill the requested number of groups.
def in_groups(number)
group_size = size / number
leftovers = size % number
groups = []
start = 0
number.times do |index|
length = group_size + (leftovers > 0 && leftovers > index ? 1 : 0)
groups << slice(start, length)
start += length
end
groups
end
Try
a.in_groups_of(3,false)
It will do your job
As mltsy wrote, in_groups(n, false) should do the job.
I just wanted to add a small trick to get the right balance
my_array.in_group(my_array.size.quo(max_size).ceil, false).
Here is an example to illustrate that trick:
a = (0..8).to_a
a.in_groups(4, false) => [[0, 1, 2], [3, 4], [5, 6], [7, 8]]
a.in_groups(a.size.quo(4).ceil, false) => [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
This needs some better cleverness to smear out the extra pieces, but it's a reasonable start.
def i_need(bits, r)
c = r.count
(1..bits - 1).map { |i| r.shift((c + i) * 1.0 / bits ) } + [r]
end
> i_need(2, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3, 5, 7], [2, 4, 6, 8]]
> i_need(3, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3, 5], [7, 2, 4], [6, 8]]
> i_need(5, [1, 3, 5, 7, 2, 4, 6, 8])
=> [[1, 3], [5, 7], [2, 4], [6], [8]]

A more balanced array manipulation than each_slice?

I have an array of 10 items and I want to split it up into 3 sections that look like this:
[1, 2, 3, 4]
[5, 6, 7]
[8, 9, 10]
Using each_slice I can get close:
a = *(1..10)
a.each_slice(4) # use 4 so I can fit everything into 3 sections
[1, 2, 3, 4]
[5, 6, 7, 8]
[9, 10]
But I want the first format which is more evenly distributed. I can do it writing my own method. But is there a built in way to do this in ruby 1.9+?
Update:
Since there's no built in way I'd like to change my question to - how would you implement it?
Here's my implementation
def chunk(a, pieces)
size = a.size / pieces
extra = a.size % pieces
chunks = []
start = 0
1.upto(pieces) do |i|
last = (i <= extra) ? size.next : size
chunks << a.slice(start, last)
start = chunks.flatten.size
end
chunks
end
call it like so
a = *(1..10)
puts chunk(a, 3)
will output
[1, 2, 3, 4]
[5, 6, 7]
[8, 9, 10]
If piece size is too big it pads with empty arrays
a = *(1..10)
puts chunk(a, 14)
will output
[[1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [], [], [], []]

Resources