I'm new to Ruby, how can I count elements in a loop?
In Java I would write it like this
int[] tablica = { 23,53,23,13 };
int sum = 0;
for (int i = 0; i <= 1; i++) { // **only first two**
sum += tablica[i];
}
System.out.println(sum);
EDIT: I want only first two
You can sum all the elements in an array like this:
arr = [1,2,3,4,5,6]
arr.inject(:+)
# any operator can be here, it will be
# interpolated between the elements (if you use - for example
# you will get 1-2-3-4-5-6)
Or, if you want to iterate over the elements:
arr.each do |element|
do_something_with(element)
Or, if you need the index too:
arr.each_with_index do |element, index|
puts "#{index}: #{element}"
tablica.take(2).reduce(:+)
But seriously? What's wrong with just
tablica[0] + tablica[1]
Hey, it even works in Ruby and Java … and C, C++, Objective-C, Objective-C++, D, C#, ECMAScript, PHP, Python. Without changes.
There are many ways, but if you want the current object and a counter use the each_with_index method
some_collection.each_with_index do |o, i|
# 'o' is your object, 'i' is your index
end
EDIT: Oops, read that too quickly. You can do this
sum = 0
some_collection.each { |i| sum += i }
With Enumerable#inject:
tablica = [23, 53, 23, 13]
tablica.inject(0, :+) # 112
If you just need a sum, here is a simple way:
tablica = [ 23,53,23,13 ]
puts tablica.inject(0){|sum,current_number| sum+current_number}
For first two elements (or whatever contiguous range) you can use a range:
tablica = [ 23,53,23,13 ]
puts tablica[0..1].inject(0){|sum,current_number| sum+current_number}
What this does:
The block (the statement within {...}) is called internally by inject, once for each element in the array.
At the first iteration, sum has the initial value 0 (that we passed to inject)
And current_number contains the 0th element in the array.
We add the two values (0 and 23) and this value gets assigned to sum when the block returns.
Then on the next iteration, we get sum variable as 23 and current_number as 53. And the process repeats.
Related
My teacher asked me to write a Ruby program that contain a loop and in each iteration it randomly makes a choice: head (represented by 1) or tail (represented by 0), and stores the outcome (0 or 1) in an array. I am not sure how to store my outcome into an array and this is my code
p "Select a number between 50 to 100"
x = gets.to_i
i = 0
array[x]
while i < x
a = rand(0..1)
array.push(a)
i += 1
end
Hay, may you can try the following:
number_of_times = gets.to_i
array = []
number_of_times.times do
random_result = rand(0..1)
array.push(random_result)
end
or (like the comments)
n = gets.to_i
array = n.times.map{ rand(0..1) }
After executing this, array will have the result of all randomized options.
Note1: You don't need to initialize array with the width, you can just initialize the array and push elements to him.
Note2: No problems with your while operator, but in ruby, you have the .times iterator, is more legible for this case.
You can leverage Ruby's Array block constructor to allocate and initialize your array in a one-liner:
array = Array.new(n) { rand(0..1) } # sample result: [0, 0, 1, 0, 1, 0] for n = 6
The argument n determines the size of the array, and the block argument is used to initialize each of the n elements.
I was doing this question on codewars: "Given an array, find the int that appears an odd number of times. There will always be only one integer that appears an odd number of times."
Code:
def find_it(seq)
int = []
for a in seq do
count = 0
for b in seq do
if a == b
count += 1
end
end
if count % 2.0 != 0
int << b
end
end
puts int.uniq[0].to_i
end
It was tested against a couple inputs, but the answers were wrong for these two arrays:
find_it([1,1,2,-2,5,2,4,4,-1,-2,5]) - returns 5 instead of -1
find_it([1,1,1,1,1,1,10,1,1,1,1]) - returns 1 instead of 10
What went wrong with my code?
if count % 2.0 != 0
int << b
end
The problem you have here is that your pushing b instead of a into the integer array, so what's happening is that instead of the value that you counted being pushed in, your pushing in the last value of b which is the last value element in the array regardless as long as the condition that the counter is an odd number, although b and counter have nothing to do with each other. so to fix it you replace b with a so that it pushes in the value you are testing comparing with the other elements in the second loop
fix:
if count % 2.0 != 0
int << a
end
a similar yet simpler code that does a similar job except in a shorter and more understandable way is:
def find_it(seq)
numberWithOddCount = 0
seq.each do |currentElement|
counter = 0
seq.each { |elementToCompare| counter += 1 if currentElement == elementToCompare}
numberWithOddCount = currentElement if counter % 2 != 0
end
numberWithOddCount
end
Just added a few tid-bits that you could also utilize to shorten and simplify code.
Happy Coding!
Note:
You could utilize built in ruby methods in creative ways to make the code do what you want in very few lines (or even one line) such as what #iGian did in the questions comments, but if your still new to ruby then its best to utilize those methods one by one when learning them otherwise you'll be confused. But if your willing to take the time now to learn them, I suggest you take his code and separate each method execution into its own line and output what each method had done to know what's doing what. and practice using each separately.
#aimen_alt is right about your mistake
but let's decompose your problem.
First, you need to calculate the appearances of each number.
Second, you need to find the one with the odd count of the appearances.
Accordingly to the problem, there is only one such number, so you can return it right away.
You can go your way and do it in O(N^2) complexity by scanning your sequence for each item in the sequence (so N items in the sequence multiply by the size of the sequence N = N*N). You can do it linearly* by constructing a Hash and than you'll be able to get the key with odd value:
def find_it(seq)
numbers = {}
seq.each do |item|
numbers[item] = numbers[item].to_i + 1
end
numbers.select{ |k,v| v.odd? }.first.first
end
to be more idiomatic you can use group_by to group the numbers themselves:
seq = [1, 2, 6, 1, 2]
seq.group_by{ |item| item }
#=> {1=>[1, 1], 2=>[2, 2], 6=>[6]}
You can see that each value is an Array, and you just need to get one with the odd amount of items:
seq = [1, 2, 6, 1, 2]
seq.group_by{ |item| item }.select{ |k, v| v.size.odd? }
#=> {6=>[6]}
And the last thing you would like to do is to get the value of the key:
seq.group_by{ |item| item }.select{ |k, v| v.size.odd? }.keys.first
So, the final solution would be
def find_it(seq)
seq.group_by{ |item| item }
.select{ |k, v| v.size.odd? }
.keys
.first
end
as #pascalbetz mentioned:
def find_it(seq)
seq.group_by{ |item| item }
.find{ |k, v| v.size.odd? }
.first
end
def find_it(seq)
seq.group_by{|x| x}.select{|k, v| (v.count % 2.0 !=0)}.first[0]
end
The above code will take a sequence in an array. Here we are grouping by elements:
For example:
[1,1,2,-2,5,2,4,4,-1,-2,5].group_by{|x| x}
# => {1=>[1, 1], 2=>[2, 2], -2=>[-2, -2], 5=>[5, 5], 4=>[4, 4], -1=>[-1]}
after getting the above results, we are finding the whose elements count not odd with the select condition.
ex:
[1,1,2,-2,5,2,4,4,-1,-2,5].group_by{|x| x}.select{|k, v| (v.count % 2.0 !=0)}
we will get the results as {-1=>[-1]}
we are taking the key as result element.
What about this one
def find_it(seq)
seq.reduce(:^)
end
^ -> this symbol is bitwise XOR.
reduce function is taking each value and doing whatever work assigned inside. In this case, it's taking each element and doing an XOR operation. the first element is doing XOR with zero and the next element doing XOR with the previous result and so on.
In this way, we found the odd element.
How XOR operation work
0 ^ 2 = 2
4 ^ 4 = 0
If you want to know more about XOR. kindly refer to this.
Thank you for all the detailed answers, I'm going over everyone's answers now. I'm new to Ruby, and I'm still in the process of learning the methods/rules of using them/Big O notation, so I much appreciated everyone's input. Codewar listed some top ranked solutions. This seems to be the fastest so far:
def find_it(seq)
seq.detect { |n| seq.count(n).odd? }
end
thanks for clicking. I'm learning Ruby from this tutorial.
And here's a bit of code for a method that gives square values.
def first_square_numbers(number_of_squares)
squares = []
idx = 0
while idx < number_of_squares
squares.push(idx * idx)
idx = idx + 1
end
return squares
end
puts("How many square numbers do you want?")
number_of_desired_squares = gets.to_i
squares = first_square_numbers(number_of_desired_squares)
idx = 0
while idx < squares.length
puts(squares[idx])
idx = idx + 1
end
# Output:
# How many square numbers do you want?
# 7
# 0
# 1
# 4
# 9
# 16
# 25
# 36
My question is, in order to print the output, instead of this code:
idx = 0
while idx < squares.length
puts(squares[idx])
idx = idx + 1
end
Can I just put this?
puts(squares)
I tried it and got the same result but I'm not sure which is "more correct" and why.
Thanks!
puts squares
is, without doubts, more correct since it's an idiomatic Ruby. Another option is to use the each iterator method:
squares.each { |n| puts n }
But in this case puts is enough.
Yes you should use puts squares instead (no need for the parentheses here either) because it's more readable and cleaner and well there's no need to re-invent the wheel etc.
Although your overall code works fine, in Ruby it would be better to do something like:
puts "How many squares do you want?"
puts (1..gets.to_i).map {|i| i**2 }
How it works...
Suppose the user enters 7:
1..gets.to_i #creates a range from 1 to the user's input
#=> 1..7
map {|i| i**2 } #takes each element from 1..7, squares it and puts in an array
#=> [1, 4, 9, 16, 25, 36, 49]
puts #prints out each element of the above array on a new line:
#=>
#1
#4
#9
#16
#25
#36
#49
For further information see documentation for Range and Enumerable#map.
If you call puts with an array, it will print out the elements line by line. The behavior is exactly the same as your loop version.
See the documents here
If called with an array argument, writes each element on a new line.
P.S. It's more practical to use built-in iteration methods to operate on all the elements in an array:
squares.each do |square|
puts(square)
# possibly some other operations on the element
end
This question was asked somewhere else, but I just wanted to check if what I did was applicable given the rspec circumstances:
Write a method that takes two sorted arrays and produces the sorted array that combines both.
Restrictions:
Do not call sort anywhere.
Do not in any way modify the two arrays given to you.
Do not circumvent (2) by cloning or duplicating the two arrays, only to modify the copies.
Hint: you will probably need indices into the two arrays.
combine_arrays([1, 3, 5], [2, 4, 6]) == [1, 2, 3, 4, 5, 6]
Can you just combine the two arrays into a single array and then run a typical bubble sort?
def combine_arrays(arr1,arr2)
final = arr1 + arr2
sorted = true
while sorted do
sorted = false
(0..final.length - 2).each do |x|
if final[x] > final[x+1]
final[x], final[x+1] = final[x+1], final[x]
sorted = true
end
end
end
final
end
p combine_arrays([1,3,5],[2,4,6]) => [1, 2, 3, 4, 5, 6]
Here is a variant which relies solely on Ruby's enumerators. The result is short and sweet.
# merge two sorted arrays into a sorted combined array
def merge(a1, a2)
[].tap do |combined|
e1, e2 = a1.each, a2.each
# The following three loops terminate appropriately because
# StopIteration acts as a break for Kernel#loop.
# First, keep appending smaller element until one of
# the enumerators run out of data
loop { combined << (e1.peek <= e2.peek ? e1 : e2).next }
# At this point, one of these enumerators is "empty" and will
# break immediately. The other appends all remaining data.
loop { combined << e1.next }
loop { combined << e2.next }
end
end
The first loop keeps grabbing the minimum of the two enumerator values until one of the enumerators runs out of values. The second loop then appends all remaining (which may be none) values from the first array's enumerator, the third loop does the same for the second array's enumerator, and tap hands back the resulting array.
Sure, you can do that but you are overlooking a real gimmee - the two arrays you are given will already be sorted.
def combine_arrays(A1, A2)
retVal = Array.CreateInstance(System::Int32, A1.Length + A2.Length - 1)
i = 0
j = 0
while i < A1.Length | j < A2.Length
if i < A1.Length and self.A1(i) < self.A2(j) then
self.retVal(i + j) = self.A1(i)
i += 1
else
self.retVal(i + j) = self.A2(j)
j += 1
end
end
return retVal
end
This is based on the same logic as Dale M's post, but in proper ruby:
def combine_arrays(arr1,arr2)
[].tap do |out|
i1 = i2 = 0
while i1 < arr1.size || i2 < arr2.size
v1 = arr1[i1]
v2 = arr2[i2]
if v1 && (!v2 || v1 < v2)
out << v1
i1 += 1
else
out << v2
i2 += 1
end
end
end
end
combine_arrays([1,3,5], [2,4,6])
Take a look at this one:
def merge(arr1, arr2)
arr2.each { |n| arr1 = insert_into_place(arr1, n) }
arr1.empty? ? arr2 : arr1
end
def insert_into_place(array, number)
return [] if array.empty?
group = array.group_by { |n| n >= number }
bigger = group[true]
smaller = group[false]
if bigger.nil?
number > smaller.last ? smaller << number : smaller.unshift(number)
else
(smaller << number) + bigger
end
end
I have an array that contains values that I'm working on (in a specific order) something like the following:
myArray = [3,6,5,6,2,1]
I need to evaluate the elements in the array and determine the number of the elements to copy.
The rules are: I need to copy the elements where the sum of those elements is not greater than the previous element.
I can kind of express it like this:
if myArray[-3] > (myArray[-2] + myArray[-1])
elements_to_copy = [myArray[-2],myArray[-1]]
else
elements_to_copy = [myArray[-1]]
end
Which feels very crappy, as I can't work out how to make it work as an iterative function, so that I can continue up the chain till the comparison fails.
Can anyone help?
myArray = [3,5,6,2,1]
i = 0
myArray.reverse.inject do |sum, cur|
break if cur < sum
i -= 1
sum + cur
end
The range to copy is i..-1.
elements_to_copy = []
array = myArray.reverse
array.each_with_index do |item, index|
if array.values_at[0..[index-1,0].max].sum <= item
elements_to_copy << item
end
end
Should do the trick, if I understand you correctly.