Swap elements in array without creating new array [closed] - arrays

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I was asked for a method to return the arr if element == 5 to be pushed to the end of the array and if its not 5 to be pushed to the beginning of the arr have to do this without creating new array
could you please help me solve this one time with iterating .each
and another without .each
Using ruby
Ruby please
end
puts put_num5_last([5,3,5,2,5,1,4])

You can use the sort_by! method of Array.
In ruby there is a naming convention that methods ending with ! are either inplace or destructive, that is they modify the receiver.
sort_by will return a new array (sorted), sort_by! will sort the array inplace.
input = [6, 5, 3, 5, 2, 5, 1, 4]
output = input.sort_by! do |a, b|
if a == 5
1
else
-1
end
end
p input #=> [4, 2, 1, 6, 3, 5, 5, 5]
p output #=> [4, 2, 1, 6, 3, 5, 5, 5]
p input.object_id #=> 70191237292740
p output.object_id #=> 70191237292740
p input.object_id == output.object_id #=> true

You could fish the fives out of the array, and concatenate them to the end.
numbs = [5, 3, 5, 2, 5, 1, 4]
fives = numbs.select { |numb| numb == 5 }
numbs.delete(5)
numbs.concat(fives)
numbs #=> [3, 2, 1, 4, 5, 5, 5]
This is not the most efficient solution, since both select and delete iterate over the full array. But this is the most readable. More efficient, but less readable would be:
numbs = [5, 3, 5, 2, 5, 1, 4]
# reverse loop to prevent shifting of elements that are not yet iterated
numbs.each_index.reverse_each do |index|
next unless numbs[index] == 5
numbs << numbs.delete_at(index)
end
numbs #=> [3, 2, 1, 4, 5, 5, 5]
The above only loops once over the array, removing the value from the array and appending it to the end.

Related

Sorting an array according to an element inside this array

I need to order my array according to an element of it, the reference element can vary.
For example, I would like the 3 to become the first element of the array and the 1, 2 to be put at the end.
array = [1, 2, 3, 4, 5, 6]
new_array = [3, 4, 5, 6, 1, 2]
The element may vary. If I start from 5, the behavior must be the same: the elements that precede are placed at the end, so I will have :
new_array = [5, 6, 1, 2, 3, 4]
If I understand correctly you want to rotate the array.
array
# [1, 2, 3, 4, 5, 6]
array.rotate(2) # or array.rotate(array.index(3))
# [3, 4, 5, 6, 1, 2]
https://apidock.com/ruby/v2_5_5/Array/rotate
Definitely use #rotate for this in actual use, but as an alternative, you could do something like #shift and #push until the desired element is at the beginning of the array.
def rotate(arr, elem)
arr2 = arr.clone
arr2.push(arr2.shift) until arr2.first == elem
arr2
end
irb(main):026:0> arr = [1, 2, 3, 4, 5, 6]
=> [1, 2, 3, 4, 5, 6]
irb(main):027:0> rotate(arr, 3)
=> [3, 4, 5, 6, 1, 2]
irb(main):028:0> arr
=> [1, 2, 3, 4, 5, 6]
Clearly, if elem is not in arr, this will run forever. You could implement some kind of check to ensure this doesn't happen, but that's just one reason you shouldn't actually do this as anything other than a learning exercise.
One approach would be to find the index of elem in arr and shift/push that many times. The &. operator may be useful in that situation to deal with the possibility of not finding elem in arr.

How to find array elements that are the sum of a given number

For example, we have such array arr = [1, 1, 3, 4, 5, 7] and we have given number 8, we need to find any n number of elements in this array that will be the sum of the given number. In this case, it should be [1, 3, 4] or [1, 7] or [3, 5]. What is the easiest way to do it in Ruby?
Like #Stefan and #Jorg said in comments there is no easy way to do it. If this was a question to myself, I would probably write down something like this.
arr = [1, 1, 3, 4, 5, 7]
number = 8
result = []
for i in 0..(arr.length) do
arr.combination(i).each do |combination|
result.push(combination) if combination.sum == number
end
end
print result.uniq
Depending on the magnitude of the given number, it may be faster to use dynamic programming. If tot is the given number and arr is the array of possible summands, the method given below has a computational complexity of O(tot*arr.size).
Code
def find_summands(arr, tot)
return [] if tot.zero?
arr.each_with_object([{tot=>nil}]) do |n,a|
h = a.last.each_key.with_object({}) do |t,h|
return soln(arr,a.drop(1),n) if t==n
h[t] = 0
h[t-n] = n
end
a << h
end
nil
end
def soln(arr,a,n)
t = n
a.reverse.each_with_object([n]) do |h,b|
m = h[t]
b << m
t += m
end.reverse.tap { |a| (arr.size-a.size).times { a << 0 } }
end
Examples
arr = [1, 1, 3, 4, 5, 7]
find_summands(arr, 8)
#=> [1, 0, 3, 4, 0, 0]
find_summands(arr, 11)
#=> [1, 1, 0, 4, 5, 0]
find_summands(arr, 21)
#=> [1, 1, 3, 4, 5, 7]
find_summands(arr, 22)
#=> nil
find_summands([1, -2, 3, 4, 5, 7], 6)
#=> [1, -2, 3, 4, 0, 0]
Each zero in the array returned indicates that the corresponding element in arr is not used in the summation.
Explanation
Suppose:
arr = [4, 2, 6, 3, 5, 1]
tot = 13
then
find_summands(arr, tot)
#=> [4, 0, 6, 3, 0, 0]
When a solution is obtained soln is called to put it into a more useful form:
soln(arr, a.drop(1), n)
Here, arr is as above and
n #=> 3
a #=> [
{13=>nil}, # for tot
{13=>0, 9=>4}, # for arr[0] => 4
{13=>0, 11=>2, 9=>0, 7=>2}, # for arr[1] => 2
{13=>0, 7=>0, 11=>0, 5=>6, 9=>0, 3=>6, 1=>6} # for arr[2] => 6
]
n equals the value of the last summand used from arr, left to right.
When considering arr[0] #=> 4 the remaining amount to be summed is 13, the key of a[0] #=> {13=>nil}. There are two possibilities, 4 is a summand or it is not. This gives rise to the hash
a[1]
#=> {13-0=>0, 13-4=>4}
# { 13=>0, 9=>4}
where the keys are the remaining amount to be summed and the value is 4 if 4 is a summand and is zero if it is not.
Now consider arr[1] #=> 2. We look to the keys of a[1] to see what the possible remaining amounts might be after 4 is used or not. (13 and 9). For each of these we consider using or not using 2. That gives rise to the hash
a[2]
#=> {13-0=>0, 13-2=>2, 9-0=>0, 9-2=>2}
# { 13=>0, 11=>2, 9=>0, 7=>2}
7=>2 can be read, if 2 (the value) is a summand, there is a choice of using arr[0] or not that results in the remaining amount to be summed after 2 is included being 7.
Next consider arr[2] #=> 6. We look to the keys of a[2] to see what the possible remaining amounts might be after 4 and 6 are used or not. (13, 11, 9 and 7). For each of these we consider using or not using 6. We therefore now create the hash
a[3]
#=> {13-0=>0, 13-6=>6, 11-0=>0, 11-6=>6, 9-0=>0, 9-6=>6, 7-0=>0, 7-6=>6}
# { 13=>0, 7=>6, 11=>0, 5=>6, 9=>0, 3=>6, 7=>0, 1=>6}
# { 13=>0, 11=>0, 5=>6, 9=>0, 3=>6, 7=>0, 1=>6}
The pair 11=>0 can be read, "if 6 is not a summand, there is a choice of using or not using arr[0] #=> 4 and arr[2] #=> 2 that results in the remaining amount to be summed after 6 is excluded being 11".
Note that the key-value pair 7=>6 was overwritten with 7=>0 when not using 6 was considered with a remaining amount of 7. We are only looking for one solution, so it doesn't matter how we get to a remaining amount of 7 after the first three elements of arr are considered. These collisions tend to increase as we move left-to-right in arr, so the number of states we need to keep track of is greatly reduced because we are able to "throw away" so many of them.
Lastly (as it turns out), we consider arr[3] #=> 3. We look to the keys of a[3] to see what the possible remaining amounts might be after 4, 2 and 6 have been used or not (13, 11, 5, 9, 3, 7 and 1). For each of these we consider using or not using 3. We get this far in creating the hash a[4]:
{13=>0, 10=>3, 11=>0, 8=>3, 5=>0, 2=>3, 9=>0, 6=>3, 3=>0, 0=>3}
As the last key-value pair has a key of zero we know we have found a solution.
Let's construct the solution. Because the value of 0 is 3, 3 is a summand. (We would have found the solution earlier if the value were zero.) We now work backwards. As 3 is used, the remaining amount before 3 is used is 0+3 #=> 3. We find that a[3][3] #=> 6, meaning 6 is also a summand. The remaining balance before using the 6 was 3+6 #=> 9, so we compute a[2][9] #=> 0, which tells us that the 2 is not a summand. Lastly, a[1][9-0] #=> 4 shows that 4 is also a summand. Hence the solution
[4, 0, 6, 3, 0, 0]

Ruby save modified array in a variable without it changing the original array

I'd like to save in two variables the values of an array excluding the first and last elements.
For example:
prices = [9, 3, 5, 2, 1]
The elements I need are:
prices_excl_first = [3, 5, 2, 1]
prices_excl_last = [9, 3, 5, 2]
I figured out how to remove an element from an array a few ways, including slicing off the value by passing its index to the slice method like so:
first_price = prices.slice(0)
last_price = prices.slice(-1)
We could then save the modified arrays into variables:
array_except_first_price = prices.delete(first_price) #=> [3, 5, 2, 1]
array_except_last_index = prices.delete(last_price) #=> [3, 5, 2]
There are two problems with this:
array_except_last_index doesn't contain the first element now
I still need access to the full, original array prices later
So essentially, how can I just temporarily modify the elements in the array when necessary in the problem?
Slicing and dropping elements from array permanently affect the array.
Ruby has first and last to copy just the first and last elements.
Ask for the first and last prices.size-1 elements.
prices = [9, 3, 5, 2, 1]
except_first = prices.last(prices.size-1)
except_last = prices.first(prices.size-1)
#Schwern's answer is probably the best you can get. Here's the second best:
prices = [9, 3, 5, 2, 1]
prices[1..-1] # => [3, 5, 2, 1]
prices[0..-2] # => [9, 3, 5, 2]
Or drop/take (which more closely map to the wording of your question).
prices.drop(1) # => [3, 5, 2, 1]
prices.take(prices.size-1) # => [9, 3, 5, 2]
You could use each_cons:
a, b = prices.each_cons(prices.size - 1).to_a
a #=> [9, 3, 5, 2]
b #=> [3, 5, 2, 1]
Splat it.
*a, d = prices
c, *b = prices
a #=> [9, 3, 5, 2]
b #=> [3, 5, 2, 1]
You can use dup to duplicate the array before performing destructive operations.
prices = [9, 3, 5, 2, 1]
except_first = prices.dup
except_first.delete_at 0
except_last = prices.dup
except_last.delete_at -1
This does end up duplicating the array a couple of times. If you're dealing with large arrays, this may be a problem.

How do I remove the beginning elements of my array only if the first element satisfies a condition?

In Ruby, let's say I have an array of ordreed, unique numbers
[0, 1, 2, 4, 6, 8, 10]
If the first element of the array is zero, how do I remove all the elements from teh beginning of the array that are consecutive, starting wiht zero? That is, in the above example, I would want to remove "0", "1", and "2" leaving me with
[4, 6, 8, 10]
But if my array is
[1, 2, 3, 10, 15]
I would expect the array to be unchanged because the first element is not zero.
You could use a mix of drop_while and with_index to only remove the first matching elements:
[0, 1, 2, 4, 6, 8, 10].drop_while.with_index{|x, i| x == i}
# [4, 6, 8, 10]
[1, 1, 2, 4, 6, 8, 10].drop_while.with_index{|x, i| x == i}
# [1, 1, 2, 4, 6, 8, 10]
Note that the second and third elements don't get deleted in the second example, even though they're equal to their indices.
Drop elements, as long as they are equal to their index:
a=a.drop_while.with_index{|e,i| e==i}
Sounds like you're trying to delete entities if they match their idx (provided the first idx is 0). Try this:
if array.first == 0
new_array = array.reject.each_with_index{ |item, idx| item == idx }
end
Although this will only work with ordered arrays of unique numbers, if you're not sure that they are then include: array = array.sort.uniq
You could do:
x = -1
while my_array.first == x + 1 do
x = my_array.shift
end
Note that array.shift is the same as array.pop except that it works from the start of the array.
If I understand you right, then it can be one of possible solutions:
def foo(array)
if array.first.zero?
array.keep_if.with_index { |e, ind| e != ind }
else
array
end
end
> foo([0, 1, 2, 5, 6, 7])
#=> => [5, 6, 7]
> foo([1, 2, 3])
#=> [1, 2, 3]
In short form:
a[0] == 0 ? a[3..-1] : a
In longer form:
if a.first == 0
a[3..(a.size)]
else
a
end

trying to sum array element values from two different arrays [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I'm trying to sum the value of two array elements from two separate arrays from end to beginning, to see if that sum is greater than 9.
I have tested my code and the part which doesn't work is.
if halfa[i] + halfb[i] > 9
Does anyone know where i'm going wrong? Any help would be much appreciated.
text = gets.chomp
half1 = text.slice(0,10)
half2 = text.slice(text.length - 10,text.length)
puts half1
puts half2
halfa = half1.split("")
halfb = half2.split("")
halfa.map! { |i| i.to_i }
halfb.map! { |i| i.to_i }
count = 0
for i in halfa.length.downto(0)
if halfa[i] + halfb[i] > 9
count += 1
end
end
print count
You've got an off-by-one error here, one of the classic programming mistakes, you start iterating at i being the length of the array, yet halfa[5] is nil, the array goes from 0 to 4.
The problem here is you're using the clunky for loop method for iterating. Ruby, unlike nearly every other language, shuns that in favour of using iterator methods:
halfa.each_index do |i|
if halfa[i] + halfb[i] > 9
count += 1
end
end
That's the most literal translation of what you have. Note you can clean up your code considerably if it's expressed in a more Ruby-like notation:
text = "4443466664"
# Define a variable here that represents the slice size to use
slice_size = 5
# Cut this into groups of 5 characters, convert each chunk by remapping
# the values to integers, then save it all into one variable.
halves = text.chars.each_slice(slice_size).map { |a| a.map(&:to_i) }
# The result looks like this:
# => [[4, 4, 4, 3, 4], [6, 6, 6, 6, 4]]
# Count all pairs that add up to more than 9 using count with a block
# that defines when to count them. Note the use of ... which goes up to
# but does not include the upper bound.
count = (0...slice_size).count do |i|
halves[0][i] + halves[1][i] > 9
end
# => 3
One way to refactor your code would be with Array#zip and Enumerable#count:
text = "123456789098765"
n = 10
digits = text.chars.map(&:to_i)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 9, 8, 7, 6, 5]
first = digits.first(n)
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
last = digits.last(n)
# [6, 7, 8, 9, 0, 9, 8, 7, 6, 5]
pairs = first.zip(last)
# [[1, 6], [2, 7], [3, 8], [4, 9], [5, 0], [6, 9], [7, 8], [8, 7], [9, 6], [0, 5]]
count = pairs.count{ |a, b| a + b > 9 }
# 6
for i in halfa.length.downto(0) : halfa.length is 10, but arrays have zero-based indices: start counting with 0. halfa[10] does not exist.
for i in (halfa.length-1).downto(0) will result in - well, at least something.
Your for loop is going to start at halfa.length, which is 10. The highest index in in halfa is 9, so halfa[10] returns nil.
You could fix it by changing halfa.length to (halfa.length - 1), but you would still have some very unidiomatic code. In Ruby it's rare to see for, because there is pretty much always a better alternative. For example:
text = "31415926535897932384"
half_size = text.size / 2
count = half_size.times.count do |i|
text[i].to_i + text[i+half_size].to_i > 9
end
puts count
# => 4
The above code assumes that the text will have an even number of characters. You could also hard-code half_size to 10 if you wanted.
The Integer#times method will enumerate the numbers 0 through its receiver, so e.g. 5.times.to_a returns [0, 1, 2, 3, 4]. The Array#count method returns the number of times the block yielded a truthy value.
See it on repl.it: https://repl.it/FXpa

Resources