So I have this function.
array = Array.new
def put_array(array)
l = array.index(array[-1])
puts l
for i in 0...l do
puts array[i]
end
end
put_array([1, 2, 3, 4, 5, 6])
the output is to print the array but I keep getting this result.......
5
1
2
3
4
5
Error ::The index output is 5, whereas the expected output should be 6. I have tried rindex,array.last instead of array[-1] but I keep getting same answer
I'm not exactly sure what your expected output was.
But your error comes from the fact that array indexing in ruby is zero-based, ie they start at 0. Therefore :
Despite your array having 6 elements, the index of its last element is 5.
This also mean that when you start iterating through your array with an index value of 1, you are starting with its second element.
On a different note, with 1...l you are defining an exclusive range, that is a range of integers from 1 to l, excluding l. If you want to include l, you need to use 1..l
A quickfix to your code would be :
for i in 0..l do
puts array[i]
end
But a more idiomatic way of achieving the same output would be :
array.each {|e| puts e}
Also
l = array.index(array[-1])
looks a bit convoluted. Why not simply ?
l = array.length
If you simply puts array it will print each element of array in new line:
array = [1, 2, 3, 4, 5, 6]
puts array
#=> Output:
1
2
3
4
5
6
def put_array(array)
puts array
end
> put_array(array)
If you want to perform on index basis:
> array.each_with_index {|e,i| puts array[i]}
I think you are confused because 0...5 outputs the number range 0,1,2,3,4 and not 0,1,2,3,4,5. You need to use .. rather than ... at the line starting for i in
def put_array(array)
l = array.index(array[-1])
puts l
for i in 0..l do
puts array[i]
end
end
put_array([1, 2, 3, 4, 5, 6])
That will output:
5
1
2
3
4
5
6
Though as others have stated, there are easier ways to achieve the same output.
I am not sure if you are trying to print the array, if it so .. your code can be modified this way
array = Array.new
def put_array(array)
l = array.length
for i in 0...l do
puts array[i]
end
end
put_array([1, 2, 3, 4, 5, 6])
index gives you the index for the given object, so in your case index(-1) will give nil because the array does not contain -1.
Instead you want to do this:
array.index(6) # => 5 (6 is at index 5 of array)
array[5] # => 6 (5th item in array is 6)
array[-1] # => 6 (-1th (aka last) item in the array is 6)
array.last # => 6 (last item in array is 6)
Related
I'm trying to create a method that iterates through an array and add up all of its elements and returns the element that is half of its sum, else it will return nil.
Examples:
p all_else_equal([2, 4, 3, 10, 1]) #=> 10, because the sum of all elements is 20
p all_else_equal([6, 3, 5, -9, 1]) #=> 3, because the sum of all elements is 6
p all_else_equal([1, 2, 3, 4]) #=> nil, because the sum of all elements is 10 and there is no 5 in the array.
My solution was to iterate through the array and add each element together using a 'sum' variable. Then write a conditional statement stating if half of the sum is included in the arr, then return the element, else return nil. But for what ever reseason I keep getting 'nil'. Can anyone out there tell me why this is wrong? Here's my code:
def all_else_equal(arr)
sum = 0
sum_half = sum / 2
arr.each_with_index do |ele, i|
sum += ele
if sum_half == ele
return ele
else
return nil
end
end
end
console:
nil
so your code will return nil right after the first value. this is because
the return condition is in the loop. to solve this, move it out as shown below.
also, create the sum_half variable after the sum has already been
evaluated:
def all_else_equal(arr)
sum = 0
arr.each_with_index do |ele, i|
sum += ele
end
sum_half = sum / 2
if arr.include?(sum_half) #check if sum_half in array
return sum_half
else
return nil
end
end
p all_else_equal([2, 4, 3, 10, 1]) #=> 10, because the sum of all elements is 20
p all_else_equal([6, 3, 5, -9, 1]) #=> 3, because the sum of all elements is 6
p all_else_equal([1, 2, 3, 4]) #=> nil, because the sum of all elements is 10 and there is no 5 in the array.
a simpler alternative:
def all_else_equal(arr)
sum_half = arr.sum / 2
arr.include?(sum_half) ? sum_half : nil
end
p all_else_equal([2, 4, 3, 10, 1]) #=> 10, because the sum of all elements is 20
p all_else_equal([6, 3, 5, -9, 1]) #=> 3, because the sum of all elements is 6
p all_else_equal([1, 2, 3, 4]) #=> nil, because the sum of all elements is 10 and there is no 5 in the array.
I see a few things here. First, in Ruby and all imperative languages, variable assignments are evaluated only at their time of execution -- so your sum_half variable will always be equal to 0 / 2 or 0. It will not dynamically re-evaluate to always be equal to sum / 2. You would need to recompute it after every iteration of the loop for it to be accurate.
Second, from a logical perspective, your sum variable is only really the sum so far. Checking if half of it is equal to the current element is not what you want to do, because even if that's true, it doesn't mean the current element is half of the final sum. Instead, you might want to find the full sum, divide it in two, and then look for an element that matches that value.
Also, stylistically, your each_with_index is currently unnecessary because you're not using the index at all -- change it to just an each until you find a use for that index value.
#RobertNubel and #PhiAgent have great answers - I would suggest you especially work through PhiAgent's Answer.
I will only add a worked example for the first iteration of the loop so you can see exactly what is happeneing
A worked Example with Comments:
def all_else_equal(arr) ## let's say array = [1,2] is passed in as a parameter
sum = 0
sum_half = sum / 2 ## => sum_half = 0
arr.each_with_index do |ele, i| # => elem = 1 (given the first element in the array)
sum += ele # => sum is now 1
if sum_half == ele # => 0 == 1 ## this will be false
return ele
else
return nil # => nil be returned
end
end
end
#PhiAgent has a great solution to get the code working.
We have array = [4, 2, 9, 11, 2, 16]
Then we have
indexes = []
for i in array do
if i > 0 then indexes << array.find_index(i) else next end
end
When printing out the result it returns
[0, 1, 2, 3, 1, 5]
The problem is with the fourth index. It should be 4, but it's 1 and that's because index 1 and 4 of array have the same value (which is 2).
Isn't for loop (or .each) supposed to go through all the elements one by one? Why is this happening? Why is it picking up second index of array twice?
array.find_index returns the first index of an element in array matching the passed value.
If you want the index of the value you're looking for then you should be iterating with each_with_index:
indexes = []
array.each_with_index do |value, index|
indexes << index if value > 0
end
Or more compact (with just a single array allocation):
indexes = array.each_with_object([]).with_index {|(v, o), i| o << v if i > 0 }
Or allowing for multiple allocations:
indexes = array.map.with_index {|v, i| v > 0 ? i : nil }.compact
Or:
indexes.map.with_index.select {|v| v.first > 0 }.map(&:last)
Because Array#find_index returns the index of the first element it finds in the array.
Returns the index of the first object in ary such that the object is == to obj.
Just a quick question -- I'm probably overlooking something here.
The below method outputs the first 2 odd numbers correctly: [1,3]
If I'm not mistaken, shouldn't I want the length of the array to eventually equal n? As I understand it, the length of the outputted array [1,3] is 2, which also represent the first n-many odds: 2.
As such, the comparison in line 6 would now be <= rather than <
However, if I do that, first_n_odds(2) would now equal [1,3,5], which gives me the first three odds. What's going on here?
Thanks!
def first_n_odds(n)
array = []
current_number = 0
while array.length < n
if current_number % 2 == 1
array << current_number
end
current_number += 1
end
return array
end
puts first_n_odds(2) # output is [1,3]
Let's do your example with n == 2.
Iteration 1: array.length == 0.
Iteration 2: array.length == 1.
Both of these values are < 2. Now if you change < to <=, you'd have a 3rd iteration where array.length == 2 since your check happens before adding the new element to the array.
Since you seem to be fairly new to Ruby, here are some ways to define the method in a more idiomatic way:
# Mapping over a range
def first_n_odds_1(n)
(0...n).map { |x| x * 2 + 1 }
end
# Mapping over an Enumerator
def first_n_odds_2(n)
n.times.map { |x| x * 2 + 1}
end
# Using Numeric#step + Enumerable#take
def first_n_odds_3(n)
1.step(Float::INFINITY, 2).take(n)
end
# A more explicit version of the previous method
def first_n_oods_4(n)
1.step(by: 2, to: Float::INFINITY).take(n)
end
That's how I would do it:
def first_n_odds(n)
(1..(2*n)).step(2).to_a
end
puts first_n_odds(10).inspect
Output:
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
I have a cell array as shown below:
a = {[1 2 3] [5 3 6] [9 1 3]};
Now I want to remove the 1s from every array in a that contains 1 so that the output is as shown
a = {[2 3] [5 3 6] [9 3]};
I know the indices of arrays in cell array 'a' which contain 1. This can be done using for loop and a temporary variable, but this is taking a lot of time (I want to perform the operation on a cell array of size something like 1x100000. The one above is just for an example)
I want to know if there is any direct method that can do this quickly.
Pretty much anything is going to be slow with that large of a cell array. You could try to do this with cellfun but it's not necessarily guaranteed to be any faster than a for loop.
a = cellfun(#(x)x(x ~= 1), a, 'UniformOutput', false);
% a{1} =
% 2 3
% a{2} =
% 5 3 6
% a{3} =
% 9 3
As already commented by Suever, because you are using a cell array and it is a dynamic container, you don't have a choice but to iterate through each cell if you want to modify the contents. Just to be self-contained, here is the for loop approach to do things:
for ii = 1 : numel(a)
a{ii} = a{ii}(a{ii} ~= 1);
end
This may be faster as it doesn't undergo the overhead of cellfun. The code above accesses the vector in each cell and extracts out those values that are not equal to 1 and overwrites the corresponding cell with this new vector.
Using your example:
a = {[1 2 3] [5 3 6] [9 1 3]};
We get:
>> format compact; celldisp(a)
a{1} =
2 3
a{2} =
5 3 6
a{3} =
9 3
This example shows how to remove data from individual cells, and how to delete entire cells from a cell array. To run the code in this example, create a 3-by-3 cell array:
C = {1, 2, 3; 4, 5, 6; 7, 8, 9};
Delete the contents of a particular cell by assigning an empty array to the cell, using curly braces for content indexing, {}:
C{2,2} = []
This code returns
C =
[1] [2] [3]
[4] [] [6]
[7] [8] [9]
Delete sets of cells using standard array indexing with smooth parentheses, (). For example, this command
C(2,:) = []
removes the second row of C:
`
C =
[1] [2] [3]
[7] [8] [9]`
When I was trying to print a specific element in array, I have mistakenly typed the name of the same array inside [ ] as element and got some output as shown. I thought that it is taking the size of the array and printing that number of characters, which was proven to be wrong by the output.
#array = (0..10, 12);
print "#array[#array]";
prints
Use of uninitialized value in join or string at
/home/VAR121/Program/Practise_Perl/Arrays.pl line 9.
0 1 2 3 4 5 6 7 8 9 10
I went one step ahead and edited code as shown below
print "#array[#array[#array]]";
output as: `0 1 2 3 4 5 6 7 8 9 10 0` Use of uninitialized value in join or string at
/home/VAR121/Program/Practise_Perl/Arrays.pl line 9.
Now I tried to put a number inside the second array instead of again giving array name as below.
print "#array[#array[1,2,3]]";
output as
1 2 3
But no warning message this time.
What it is trying to print? and What is the reason behind this behavior.
You're creating an array slice. Start out by understanding that your array contains elements 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12.
That's a total of 12 elements (there is no value 11, but at index 11 you are storing the value 12).
Now when you use this construct: #array[#array] you're taking a slice, and requesting the values stored in indices 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, and 12. There is no element with an index of 12 in your array. The eleventh element has the value "12".
#array[] is array slice notation. For example:
my #array = (qw/apple banana cucumber date/)
#array[1,2] will return a list of (banana, cucumber) (index 1 and index 2 of #array).
Now, #array[#array] tries to take the values of the inner #array and use them as indexes of the outer #array. In your example, #array[#array] is equivalent to #array[0..10, 12]. Since one of the values of the inner array is 12, and the outer array has no index of 12, you get an undefined value warning.