Ruby Intro to Parallel Assignments - ruby-on-rails

a = [1, 2, 3, 4]
b, c = 99, *a → b == 99, c == 1
b, *c = 99, *a → b == 99, c == [1, 2, 3, 4]
Can someone please throughly explained why in Ruby the asterisk makes the code return what it returns? I understand that the if an lvalue has an asterisk, it assigns rvalues to that lvalues. However, why does '*a' make 'c' return only the '1' value in the array and why does '*a' and '*c' cancel each other out?

In both cases, 99, *a on the right-hand side expands into the array [99, 1, 2, 3, 4]
In
b, c = 99, *a
b and c become the first two values of the array, with the rest of the array discarded.
In
b, *c = 99, *a
b becomes the first value from the array and c is assigned the rest (because of the splat on the left-hand side).
The 99, *a on the right-hand side is an example of where the square brackets around an array are optional in an assignment.
A simpler example:
a = 1, 2, 3 → a == [1, 2, 3]
Or a more explicit version of your example:
example = [99, *a] → example == [99, 1, 2, 3, 4]

Related

How can i add an entire list on top of another list in Flutter

AddAll is pretty cool, but adds it at the bottom of the list.
I want to add the sorted list A on top of the sorted list B. I need list A for a different view
listA = [1, 2, 3];
listB = [4, 5, 6];
listB.addAll(listA);
// lista == [4, 5, 6, 1, 2, 3]
The easiest but maybe bad solution i can think of is to add first listA then listB to a listC.
listC = [];
listC.addAll(listA);
listC.addAll(listB);
//listc == [1, 2, 3, 4, 5, 6]
listB = []
listB.addAll(listC)
// garbage collector to gets rid of C
// listB == [1, 2, 3, 4, 5, 6];
// listA == [1, 2, 3];
This seems a bit inefficient, so I was wondering if there is a better way for this that doesn't include loops or anything thelike. Something like flutters 'addAt', like listB.addAllAt(0, listA)
To clarify, having a third list is a 'necessary evil' that i would like to avoid. I want one list that would be AB, and one list that is just A, to go back to the question, how do i add A on top of B.
While the suggest answer did not solve my issue, it gave me the right idea. I can add them with 'plus' into one of the original lists
listA = [1, 2, 3];
listB = [4, 5, 6];
listB = listA+listB;
// listB == [1, 2, 3, 4, 5, 6];
// listA == [1, 2, 3];
Thank you MendelG for the right idea!

How to get the next and previous element in an array, Ruby

I have this array and need to replace its elements by the multiplication of its previous and next.
I do the following:
array.each_with_index{|element, index|
next_element = array[index+1]
previous_element = array[index-1]
}
array.map! {|a|
if a == array.first
a = a * next_element
elsif a == array.last
a = a * previous_element
else
a = next_element * previous_element
end
}
I expect the following result:
array = [4, 1, 6, 7, 9, 3, 0] #given array
array = [4, 24, 7, 54, 21, 0, 0] #array replaced
I get the following error:
undefined local variable or method `next_element' for Arrays:Class
Is there a easy way of getting the previous and next element of a given array element?
Am I using the array.map! method right?
This would work:
array = [4, 1, 6, 7, 9, 3, 0]
[nil, *array, nil].each_cons(3).map { |l, m, r| (l || m) * (r || m) }
#=> [4, 24, 7, 54, 21, 0, 0]
The array is surrounded by nil values, so each element has neighbors. each_cons(3) then yiels each element along with its neighbors to map which multiplies the left (l) with the right (r) neighbor, falling back to the middle element (m) if one of the neighbors happens to be nil.
You can do as following,
[array[0..1].inject(:*)] + array[0..-2].map.with_index { |x,i| x * (array[i+2] || array[i+1]) }
# => [4, 24, 7, 54, 21, 0, 0]
You defined next_element and previous_element inside the loop, so they become undefined at the end. This is a simple work around of your code, I'll assume that
you want to keep first and last element unchanged. You dont need to use map
array.each_with_index do |element, index|
if element != array.first && element != array.last
array[index] = array[index+1] * array[index-1]
end
end
array => [4, 24, 168, 1512, 4536, 0, 0]
This is not what you expected, why? Because your element, array[index] will change after each iteration you can print array after each iteration to see the result
I would suggest you to use another array to save the value of array, like this
b =[]
array.each_with_index do |element, index|
b[index] = array[index]
if element != array.first && element != array.last
b[index] = array[index+1] * array[index-1]
end
end
Seems like each_cons would be a good fit here:
[array.first] + array.each_cons(3).map { |p, _, n| p * n } + [array.last]
#=> [4, 24, 7, 54, 21, 0, 0]
This needs some more work (e.g. if the array is empty this will return [nil, nil]) but I'm sure you can figure out these edge cases.

How to get a list of integers from a given set of possible integers in z3?

Minimal example is the following: Given a set of possible integers [1, 2, 3] create an arbitrary list of size 5 using z3py. Duplicates are allowed.
The expected result is something like [1, 1, 1, 1, 1] or [3, 1, 2, 2, 3], etc.
How to tackle this problem and how to implement 'choosing'? Finally, I would like to find all solutions which can be done by adding additional constraints as explained in link. Any help will be very appreciated.
The following should work:
from z3 import *
def choose(elts, acceptable):
s = Solver()
s.add(And([Or([x == v for v in acceptable]) for x in Ints(elts)]))
models = []
while s.check() == sat:
m = s.model ()
if not m:
break
models.append(m)
block = Not(And([v() == m[v] for v in m]))
s.add(block)
return models
print choose('a b c d e', [1, 2, 3])

How to remove array elements and append it to the front of the array in ruby without using any inbuilt methods?

I have an array say [1,2,3,4,5,6,7,8]. I need to take an input from the user and remove the last input number of array elements and append it to the front of the array. This is what I have achieved
def test(number, array)
b = array - array[0...(array.length-1) - number]
array = array.unshift(b).flatten.uniq
return array
end
number = gets.chomp_to_i
array = [1,2,3,4,5,7,8,9]
now passing the argument to test gives me the result. However, there are two problems here. first is I want to find a way to do this append on the front without any inbuilt method.(i.e not using unshift).Second, I am using Uniq here, which is wrong since the original array values may repeat. So how do I still ensure to get the correct output? Can some one give me a better solution to this.
The standard way is:
[1, 2, 3, 4, 5, 7, 8, 9].rotate(-3) #=> [7, 8, 9, 1, 2, 3, 4, 5]
Based on the link I supplied in the comments, I threw this together using the answer to that question.
def test(number, array)
reverse_array(array, 0, array.length - 1)
reverse_array(array, 0, number - 1)
reverse_array(array, number, array.length - 1)
array
end
def reverse_array(array, low, high)
while low < high
array[low], array[high] = array[high], array[low]
low += 1
high -= 1
end
end
and then the tests
array = [1,2,3,4,5,7,8,9]
test(2, array)
#=> [8, 9, 1, 2, 3, 4, 5, 7]
array = [3, 4, 5, 2, 3, 1, 4]
test(2, array)
#=> [1, 4, 3, 4, 5, 2, 3]
Which I believe is what you're wanting, and I feel sufficiently avoids ruby built-ins (no matter what way you look at it, you're going to need to get the value at an index and set a value at an index to do this in place)
I want to find a way to do this append on the front without any inbuilt method
You can decompose an array during assignment:
array = [1, 2, 3, 4, 5, 6, 7, 8]
*remaining, last = array
remaining #=> [1, 2, 3, 4, 5, 6, 7]
last #=> 8
The splat operator (*) gathers any remaining elements. The last element will be assigned to last, the remaining elements (all but the last element) are assigned to remaining (as a new array).
Likewise, you can implicitly create an array during assignment:
array = last, *remaining
#=> [8, 1, 2, 3, 4, 5, 6, 7]
Here, the splat operator unpacks the array, so you don't get [8, [1, 2, 3, 4, 5, 6, 7]]
The above moves the last element to the front. To rotate an array n times this way, use a loop:
array = [1, 2, 3, 4, 5, 6, 7, 8]
n = 3
n.times do
*remaining, last = array
array = last, *remaining
end
array
#=> [6, 7, 8, 1, 2, 3, 4, 5]
Aside from times, no methods were called explicitly.
You could create a new Array with the elements at the correct position thanks to modulo:
array = %w[a b c d e f g h i]
shift = 3
n = array.size
p Array.new(n) { |i| array[(i - shift) % n] }
# ["g", "h", "i", "a", "b", "c", "d", "e", "f"]
Array.new() is a builtin method though ;)

How to compare more than 3 array to find the one with highest priority

I have following array set holding priorities,
array1 = [1, 2, 1, 2, 3]
array2 = [1, 1, 1, 2, 3]
|
|
|
arrayn = [1, 3, 1, 2, 3]
I want to find out easiest way to find out the array variable which having highest priority i.e 1
It should check in a following way,
If last element of any array is lowest that should be return.
If last element of more than one array is same then previous element of that array should be matched
In above given example last 3 values of all the 3 array are same so it will check for the 2nd last element
array1 = 2
array2 = 1
array3 = 3
So it should return array2.
Please let me know if any one fail to understand the question
More Examples
Example 1
arr1 = [1,1,1,1,3]
arr2 = [3,3,3,3,2]
should return arr2
Example 2
arr1 = [2,2,2,1,3]
arr2 = [1,2,1,3,3]
should return arr1, as arr1.last == arr2.last (i.e. 3)
but arr1[3] < arr2[3] i.e. (1 < 3)
For equal sized arrays (and if I understand the question right) this should work:
arrays = [
[1, 2, 1, 1, 3],
[1, 3, 1, 2, 3],
[1, 1, 1, 2, 3],
[1, 3, 1, 1, 3]
]
p arrays[arrays.transpose.reverse.map{|el|
next if el.count(el.min) != 1
el.rindex(el.min)
}.compact[0]]
Result:
#=> [1, 1, 1, 2, 3]
Step by step: Transpose arrays and start to check from last chunk. If there is not one minimal priority skip this chunk (put nil in output), if only one - get it's index. Remove all nil elements and use first found index to print desired array.
UPDATED
If you wish to handle the case when initial array of arrays doesn't have answer you could change the code in this way:
idx = arrays.transpose.reverse.map{|el|
next if el.count(el.min) != 1
el.rindex(el.min)
}.compact[0]
p idx ? arrays[idx] : "no answer"
The result for [[1,1,1,1,1], [1,1,1,1,2], [2,1,1,1,1], [2,1,1,1,2]] will be:
#=> "no answer"
tab = [array1, array2, array3, arrayn]
i = -1
while tab.count != 1 && tab.count + i >= 0
tab = tab.select { |t| t[i] == tab.map { |j| j[i] }.min }
i = i - 1
end
result = tab[0]

Resources