ruby** reverse array without using reverse method - ruby

This is my array and custom method to reverse an array output without using the reverse method. not sure where it broke, tried running it in console, no dice.
numbers = [1, 2, 3, 4, 5, 6]
def reversal(array)
do |item1, item2| item2 <=> item1
end
p reversal(numbers)

Here's one way to handle this. This is not very efficient but works.
def reversal(array)
reversed = []
loop do
reversed << array.pop
break if array.empty?
end
reversed
end
Here is another implementation that does the same thing:
def reversal(array)
array.each_with_index.map do |value, index|
array[array.count-index-1]
end
end

So many ways... Here are three (#1 being my preference).
numbers6 = [1, 2, 3, 4, 5, 6]
numbers5 = [1, 2, 3, 4, 5]
For all methods my_rev below,
my_rev(numbers6)
#=> [6, 5, 4, 3, 2, 1]
my_rev(numbers5)
#=> [5, 4, 3, 2, 1]
#1
def my_rev(numbers)
numbers.reverse_each.to_a
end
#2
def my_rev(numbers)
numbers.each_index.map { |i| numbers[-1-i] }
end
#3
def my_rev(numbers)
(numbers.size/2).times.with_object(numbers.dup) do |i,a|
a[i], a[-1-i] = a[-1-i] , a[i]
end
end

there are so many ways to do this
1 Conventional way
a=[1,2,3,4,5,6,7,8]
i=1
while i <= a.length/2 do
temp = a[i-1]
a[i-1] = a[a.length-i]
a[a.length-i] = temp
i+=1
end
2 Using pop
a=[1,2,3,4,5,6]
i=0
b=[]
t=a.length
while i< t do
b << a.pop
i+=1
end
3 Using pop and loop
a=[1,2,3,4,5,6]
b=[]
loop do
b << a.pop
break if a.empty?
end

a = [1,2,3,4,5]
b = []
a.length.times { |i| b << a[(i+1)*-1] }
b
=> [5,4,3,2,1]

Related

Ruby Getting a max value out of a newly created array in one function

I want my function to return the longest Array within a nested array (including the array itself) so
nested_ary = [[1,2],[[1,2,[[1,2,3,4,[5],6,7,11]]]],[1,[2]]
deep_max(nested_ary)
=> [1,2,3,4,[5],6,7,11]
simple_ary = [1,2,3,4,5]
deep_max(simple_ary)
=> returns: [1,2,3,4,5]
I created a function to collect all arrays. I have to get the max value in another function.
my code:
def deep_max(ary)
ary.inject([ary]) { |memo, elem|
if elem.is_a?(Array)
memo.concat(deep_max(elem))
else
memo
end }
end
This gives me what I want:
deep_max(nested_ary).max_by{ |elem| elem.size }
Is there a way to get this max inside of the function?
def deep_max(arr)
biggest_so_far = arr
arr.each do |e|
if e.is_a?(Array)
candidate = deep_max(e)
biggest_so_far = candidate if candidate.size > biggest_so_far.size
end
end
biggest_so_far
end
deep_max [[1, 2], [[1, 2, [[1, 2, 3, 4, [5], 6, 7, 11]]]], [1, [2]]]
#=> [1, 2, 3, 4, [5], 6, 7, 11]
You can unroll it:
def deep_max(ary)
arys = []
ary = [ary]
until ary.empty?
elem = ary.pop
if elem.is_a?(Array)
ary.push(*elem)
arys.push(elem)
end
end
arys.max_by(&:size)
end
Or you can cheat, by introducing an optional parameter that changes how your recursion works on top level vs how it behaves down the rabbit hole.

Ruby: reverse, mutating list

I'm trying to write a method, which reverses a list, but not using .reverse.
Here is my code:
def reverse(list)
a = list.length
while a >= 0
list << list[a]
a = a - 1
end
list
end
print reverse([1,2,3])
My expected result isn't [3,2,1] but [1, 2, 3, nil, 3, 2, 1]
Do you have any advice how to not repeat the original list once again, but only mutate it?
This mutates the original array as requested. nil is eliminated by being aware that the last element of the list is at list[list.length-1].
def reverse(list)
a = list.length-1
while a >= 0
list << list[a]
list.delete_at(a)
a = a - 1
end
list
end
p reverse([1, 2, 3]) #=> [3, 2, 1]
A more Ruby way could be as follows:
arr.sort_by!.with_index { |_,i| -i }
I understand the list is to be reversed in place (mutated). Below are two ways to do that.
If the list is not to be mutated, simply operate on a copy:
def non_mutating_reverse(list)
reverse(list.dup)
end
#1
Use parallel assignment (sometimes called multiple assignment).
def reverse(list)
(list.size/2).times { |i| list[i], list[-1-i] = list[-1-i], list[i] }
list
end
list = [1,2,3]
reverse list #=> [3, 2, 1]
list #=> [3, 2, 1]
Notice that when the size of the list is odd (as in this example), the middle element is not moved.
#2
def reverse(list)
list.replace(list.size.times.with_object([]) { |i,a| a.unshift(list[i]) })
end
list = [1,2,3]
reverse list #=> [3, 2, 1]
list #=> [3, 2, 1]

How to get each value of inject loop

I want to get each value of inject.
For example [1,2,3].inject(3){|sum, num| sum + num} returns 9, and I want to get all values of the loop.
I tryed [1,2,3].inject(3).map{|sum, num| sum + num}, but it didn't work.
The code I wrote is this, but I feel it's redundant.
a = [1,2,3]
result = []
a.inject(3) do |sum, num|
v = sum + num
result << v
v
end
p result
# => [4, 6, 9]
Is there a way to use inject and map at same time?
Using a dedicated Eumerator perfectly fits here, but I would show more generic approach for this:
[1,2,3].inject(map: [], sum: 3) do |acc, num|
acc[:map] << (acc[:sum] += num)
acc
end
#⇒ => {:map => [4, 6, 9], :sum => 9}
That way (using hash as accumulator) one might collect whatever she wants. Sidenote: better use Enumerable#each_with_object here instead of inject, because the former does not produce a new instance of an object on each subsequent iteration:
[1,2,3].each_with_object(map: [], sum: 3) do |num, acc|
acc[:map] << (acc[:sum] += num)
end
The best I could think
def partial_sums(arr, start = 0)
sum = 0
arr.each_with_object([]) do |elem, result|
sum = elem + (result.empty? ? start : sum)
result << sum
end
end
partial_sums([1,2,3], 3)
You could use an enumerator:
enum = Enumerator.new do |y|
[1, 2, 3].inject (3) do |sum, n|
y << sum + n
sum + n
end
end
enum.take([1,2,3].size) #=> [4, 6, 9]
Obviously you can wrap this up nicely in a method, but I'll leave that for you to do. Also don't think there's much wrong with your attempt, works nicely.
def doit(arr, initial_value)
arr.each_with_object([initial_value]) { |e,a| a << e+a[-1] }.drop 1
end
arr = [1,2,3]
initial_value = 4
doit(arr, initial_value)
#=> [5, 7, 10]
This lends itself to being generalized.
def gen_doit(arr, initial_value, op)
arr.each_with_object([initial_value]) { |e,a| a << a[-1].send(op,e) }.drop 1
end
gen_doit(arr, initial_value, :+) #=> [5,7,10]
gen_doit(arr, initial_value, '-') #=> [3, 1, -2]
gen_doit(arr, initial_value, :*) #=> [4, 8, 24]
gen_doit(arr, initial_value, '/') #=> [4, 2, 0]
gen_doit(arr, initial_value, :**) #=> [4, 16, 4096]
gen_doit(arr, initial_value, '%') #=> [0, 0, 0]

How can I remove duplicates in an array without using `uniq`?

The object of my coding exercise is to get rid of duplicates in an array without using the uniq method. Here is my code:
numbers = [1, 4, 2, 4, 3, 1, 5]
def my_uniq(array)
sorted = array.sort
count = 1
while count <= sorted.length
while true
sorted.delete_if {|i| i = i + count}
count += 1
end
end
return sorted
end
When I run this, I get an infinite loop. What is wrong?
Can I use delete the way that I am doing with count?
How will it execute? Will count continue until the end of the array before the method iterates to the next index?
I did this with each or map, and got the same results. What is the best way to do this using each, delete_if, map, or a while loop (with a second loop that compares against the first one)?
Here is a clearly written example.
numbers = [1, 4, 2, 4, 3, 1, 5]
def remove_duplicates(array)
response = Array.new
array.each do |number|
response << number unless response.include?(number)
end
return response
end
remove_duplicates(numbers)
As others pointed out, your inner loop is infinite. Here's a concise solution with no loops:
numbers.group_by{|n| n}.keys
You can sort it if you want, but this solution doesn't require it.
the problem is that the inner loop is an infinite loop:
while true
sorted.delete_if {|i| i = i + count}
count += 1
end #while
you can probably do what you are doing but it's not eliminating duplicates.
one way to do this would be:
numbers = [1, 4, 2, 4, 3, 1, 5]
target = []
numbers.each {|x| target << x unless target.include?(x) }
puts target.inspect
to add it to the array class:
class ::Array
def my_uniq
target = []
self.each {|x| target << x unless target.include?(x) }
target
end
end
now you can do:
numbers = [1, 4, 2, 4, 3, 1, 5]
numbers.my_uniq
You count use Set that acts like an array with does not allow duplicates:
require 'set'
numbers = [1, 4, 2, 4, 3, 1, 5]
Set.new(numbers).to_a
#=> [1, 4, 2, 3, 5]
Try using Array#& passing the array itself as parameter:
x = [1,2,3,3,3]
x & x #=> [1,2,3]
This is one of the answer. However, I do not know how much of performance issue it takes to return unique
def my_uniq(ints)
i = 0
uniq = []
while i < ints.length
ints.each do |integers|
if integers == i
uniq.push(integers)
end
i += 1
end
end
return uniq
end

Remove from the array elements that are repeated

What is the best way to remove from the array elements that are repeated.
For example, from the array
a = [4, 3, 3, 1, 6, 6]
need to get
a = [4, 1]
My method works to too slowly with big amount of elements.
arr = [4, 3, 3, 1, 6, 6]
puts arr.join(" ")
nouniq = []
l = arr.length
uniq = nil
for i in 0..(l-1)
for j in 0..(l-1)
if (arr[j] == arr[i]) and ( i != j )
nouniq << arr[j]
end
end
end
arr = (arr - nouniq).compact
puts arr.join(" ")
a = [4, 3, 3, 1, 6, 6]
a.select{|b| a.count(b) == 1}
#=> [4, 1]
More complicated but faster solution (O(n) I believe :))
a = [4, 3, 3, 1, 6, 6]
ar = []
add = proc{|to, form| to << from[1] if form.uniq.size == from.size }
a.sort!.each_cons(3){|b| add.call(ar, b)}
ar << a[0] if a[0] != a[1]; ar << a[-1] if a[-1] != a[-2]
arr = [4, 3, 3, 1, 6, 6]
arr.
group_by {|e| e }.
map {|e, es| [e, es.length] }.
reject {|e, count| count > 1 }.
map(&:first)
# [4, 1]
Without introducing the need for a separate copy of the original array and using inject:
[4, 3, 3, 1, 6, 6].inject({}) {|s,v| s[v] ? s.merge({v=>s[v]+1}) : s.merge({v=>1})}.select {|k,v| k if v==1}.keys
=> [4, 1]
I needed something like this, so tested a few different approaches. These all return an array of the items that are duplicated in the original array:
module Enumerable
def dups
inject({}) {|h,v| h[v]=h[v].to_i+1; h}.reject{|k,v| v==1}.keys
end
def only_duplicates
duplicates = []
self.each {|each| duplicates << each if self.count(each) > 1}
duplicates.uniq
end
def dups_ej
inject(Hash.new(0)) {|h,v| h[v] += 1; h}.reject{|k,v| v==1}.keys
end
def dedup
duplicates = self.dup
self.uniq.each { |v| duplicates[self.index(v)] = nil }
duplicates.compact.uniq
end
end
Benchark results for 100,000 iterations, first with an array of integers, then an array of strings. Performance will vary depending on the numer of duplicates found, but these tests are with a fixed number of duplicates (~ half array entries are duplicates):
test_benchmark_integer
user system total real
Enumerable.dups 2.560000 0.040000 2.600000 ( 2.596083)
Enumerable.only_duplicates 6.840000 0.020000 6.860000 ( 6.879830)
Enumerable.dups_ej 2.300000 0.030000 2.330000 ( 2.329113)
Enumerable.dedup 1.700000 0.020000 1.720000 ( 1.724220)
test_benchmark_strings
user system total real
Enumerable.dups 4.650000 0.030000 4.680000 ( 4.722301)
Enumerable.only_duplicates 47.060000 0.150000 47.210000 ( 47.478509)
Enumerable.dups_ej 4.060000 0.030000 4.090000 ( 4.123402)
Enumerable.dedup 3.290000 0.040000 3.330000 ( 3.334401)
..
Finished in 73.190988 seconds.
So of these approaches, it seems the Enumerable.dedup algorithm is the best:
dup the original array so it is immutable
gets the uniq array elements
for each unique element: nil the first occurence in the dup array
compact the result
If only (array - array.uniq) worked correctly! (it doesn't - it removes everything)
Here's my spin on a solution used by Perl programmers using a hash to accumulate counts for each element in the array:
ary = [4, 3, 3, 1, 6, 6]
ary.inject({}) { |h,a|
h[a] ||= 0
h[a] += 1
h
}.select{ |k,v| v == 1 }.keys # => [4, 1]
It could be on one line, if that's at all important, by judicious use of semicolons between the lines in the map.
A little different way is:
ary.inject({}) { |h,a| h[a] ||= 0; h[a] += 1; h }.map{ |k,v| k if (v==1) }.compact # => [4, 1]
It replaces the select{...}.keys with map{...}.compact so it's not really an improvement, and, to me is a bit harder to understand.

Resources