sorting unique values in an array with Ruby - ruby

Is there a way to write a method in Ruby which takes an array of items and returns the array without any duplicates. Without using Ruby’s uniq method?
So, the output of this array [1,5,"frog", 2,1,3,"frog"] will be [1,5,"frog",2,3]

You are getting an unexpected end-of-input because you are using parenthesis instead of braces to denote the block. Try:
my_array.to_a.select{ |i| i != i }
But even this isn't quite what you'd expect. Here is an alternative:
my_array.group_by{|item| item}.keys
Hope that helps

my_array = [1, 5, "frog", 2, 1, 3, "frog"]
uniques = []
my_array.each do |x|
uniques << x unless uniques.include?(x)
end
This iterates through my_array and only pushes to uniques elements it doesn't include.

Related

getting differences between values in an array

I want to write an Array method in ruby that takes the successive values in the array and returns their differences as a new array (unshifting a '0' in at the beginning).
So feeding the array [4,7,11,16] into the method returns a new array [4,3,4,5].
1) does such a method already exist?
If not, then I think I know how to write it. However,
2) does a method already exist which allows me to test the input array and make sure it only consists of integers and/or floats?
Again, if not, I think I know how to write one.
p [4,7,11,16].unshift(0).each_cons(2).map{|a,b| b-a} # => [4, 3, 4, 5]
Keep it simple:
arr = [4,7,11,16]
last = 0
arr.map { |e| new=e-last; last=e; new }
#=> [4, 3, 4, 5]
Another way:
a = [arr.first]
enum = arr.each
loop do
a << -enum.next + enum.peek
end
a
#=> [4, 3, 4, 5]
Enumerator#peek raises a StopIteration exception when enum is at its last element. Kernel#loop handles the exception by breaking from the loop.
Regarding the first method, I am not aware of any such method in the Ruby Array class.
Regarding the second one, you can do it as explained in this answer:
your_array.all? {|i| i.is_a? Numeric }

Strange ruby for loop behavior (why does this work)

def reverse(ary)
result = []
for result[0,0] in ary
end
result
end
assert_equal ["baz", "bar", "foo"], reverse(["foo", "bar", "baz"])
This works and I want to understand why. Any explanations?
If I were to rewrite this using each instead of for/in, it would look like this:
def reverse(ary)
result = []
# for result[0,0] in ary
ary.each do |item|
result[0, 0] = item
end
result
end
for a in b basically says, take each item in the array b and assign it to expression a. So some magic happens when its not a simple variable.
The array[index, length] = something syntax allows replacement of multiple items, even 0 items. So ary[0,0] = item says to insert item at index zero, replacing zero items. It's basically an unshift operation.
But really, just use the each method with a block instead. A for loop with no body that changes state has to be one of the most obtuse and hard to read thing that doesn't do what you expect at first glance. each provides far fewer crazy surprises.
You are putting the value in ary at the first location of result. So lets say we had the array:
a = ["baz", "bar", "foo"]
So a[0,0] = 5 will make a equal to [5, "baz", "bar", "foo"]
Since you iterate over the entire array, you are inserting each element into the beginning of the result array while shifting the existing elements, thus reversing the original one.

How to iterate over part of a hash in Ruby?

h = Hash.new
(1..100).each { |v| h.store(v * 2, v*v) }
What is the best way to iterate over a given part of the hash without using the keys? For example, from element 10 to element 20? Using Ruby 1.9.3.
EDIT - In response to Dave's comment:
Originally I wanted to access the data through keys (hence the hash). But I also want to iterate by element number. BTW, each element is a hash.
So, what is the best way to design a hash of hashes or array of hashes that can be iterated by element number or accessed by key? The data looks like the following. There are missing dates.
6/23/2011 -> 5, 6, 8, 3, 6
6/26/2011 -> 6, 8, 4, 8, 5
6/27/2011 -> 8, 4, 3, 2, 7
If I understand what you're asking for, you can iterate over a portion of your hash as follows. This gives you the 1001st through 2000th values:
h.keys[1000..1999].each do |key|
# Do something with h[key]
end
I think you better use Array for that (Hash in Ruby 1.9.3 are ordered but the access method is the keys). So:
a = h.values
# or
a = h.to_a
Convert it to an array, then slice it:
h.to_a[10..20].each { |k, v| do_stuff }
Note that before Ruby 1.9, the order of elements in a hash are not guaranteed, so this will not necessarily work as you expect.
Alternatively, you could use each_with_index and skip over the unwanted elements:
h.each_with_index do |(k, v), i|
next unless (10..20).include?(i)
# do stuff
end
h = Hash.new
(1..100).each { |v| h.store(v * 2, v*v) }
#for an array of arrays
h.drop(9).take(10) #plus an optional block
#if the slice must be a hash:
slice = Hash[h.drop(9).take(10)]
But if this is an often repeating operation you might be better off using a database.

Looping on array

I'm having some trouble figuring out the right way to do this:
I have an array and a separate array of arrays that I want to compare to the first array. The first array is a special Enumerable object that happens to contain an array.
Logic tells me that I should be able to do this:
[1,2,3].delete_if do |n|
[[2,4,5], [3,6,7]].each do |m|
! m.include?(n)
end
end
Which I would expect to return
=> [2,3]
But it returns [] instead.
This idea works if I do this:
[1,2,3].delete_if do |n|
! [2,4,5].include?(n)
end
It will return
=> [2]
I can't assign the values to another object, as the [1,2,3] array must stay its special Enumerable object. I'm sure there is a much simpler explanation to this than what I'm trying. Anybody have any ideas?
You can also flatten the multi-dimensional array and use the Array#& intersection operator to get the same result:
# cast your enumerable to array with to_a
e = [1,2,3].each
e.to_a & [[2,4,5], [3,6,7]].flatten
# => [2, 3]
Can't you just add the two inner array together, and and check the inclusion on the concatenated array?
[1,2,3].delete_if do |n|
!([2,4,5] + [3,6,7]).include?(n)
end
The problem is that the return value of each is the array being iterated over, not the boolean (which is lost). Since the array is truthy, the value returned back to delete_if is always true, so all elements are deleted. You should instead use any?:
[1,2,3].delete_if do |n|
![[2,4,5], [3,6,7]].any? do |m|
m.include?(n)
end
end
#=> [2, 3]

Getting value of three consecutive elements in array

I have a large array, h, that contains several instances of a parameter called startingParam, which is always followed by two other parameters that are related but not always the same. I need to look for every instance of startingParam in the array, and push it and the next two parameters into a separate array, holdingArray.
The following code is not working, due to the fact that I am very new to Ruby. Does anybody know what I am doing wrong? Is there a better way to approach the problem?
h.each do |param|
if param == 'startingParam'
holdingArray << h.[param],
holdingArray << h.[param + 1],
holdingArray << h.[param + 2]
end
end
Thanks so much.
You can grab the chunks using #slice_before:
arr = ['startingParam', 1, 2, 'startingParam', 3, 4]
arr.slice_before('startingParam')
# => [['startingParam', 1, 2], ['startingParam', 3, 4]]
If you created the original data structure, you may want to re-consider your design, however.
Functional approach:
>> ary = ['hello', 'startingParam', 1, 2, 'xyz', 'startingParam', 3, 4, 'bye']
>> ary.each_cons(3).select { |v, *vs| v == "startingParam" }.flatten(1)
=> ["startingParam", 1, 2, "startingParam", 3, 4]
So there are a few problems. For starters, you can't subscript arrays by doing h.[anything], and you are also subscripting based on the value (and not the index). You are also checking to see if the parameter matches the literal string "starting_param" and not its value. So what I expect you want is the following:
h.each_with_index do |param, index|
if param == startingParam
holdingArray << h[index]
holdingArray << h[index+1]
holdingArray << h[index+2]
end
end
You'll also note that if the item is in the last two slots of the array, this will wrap around and grab items from the beginning of the array (due to how Ruby handles array subscripts being out of bounds).
You could also use the range slicing operation (I've changed the varnames slightly since camelcasing is bad style in ruby)
h.each_with_index do |param, index|
if param == starting_param
holding_array.push(h[index..index+2])
end
end

Resources