Related
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.
Look at the following code:
arr = [5, 4, 3, 2, 1]
arr1 = arr
arr1.sort()
print(arr, arr1)
The expected output is:
[5, 4, 3, 2, 1] [1, 2, 3, 4, 5]
As, arr1 is getting sorted and not arr.
Although, the output is:
[1, 2, 3, 4, 5] [1, 2, 3, 4, 5]
How come both lists are getting sorted?
sort() is in-place function in python and lists are pass by reference. So, if one array is getting sorted in-place it will change another, too.
If you want to prevent that, you can use:
arr = arr1[:]
or
import copy
arr = copy.deepcopy(arr1)
I'm looking for a method that is equivalent to Array#|, and whose method name is in ordinary word.
a = [1, 2, 3]
b = [3, 4, 5]
a|b # => [1, 2, 3, 4, 5]
I'm not looking for new methods. I can write any sort of method that will accomplish this. That's not what I'm asking. I'm wondering if there's an alias. Is there a method like a.merge(b) that isn't a functioning method for arrays in 2.5.1?
It's described in the documentation for version 2.5.1 that | is the same as Array.union(another_array). But it throws an error.
a.union(b) # >> undefined method `union' for [1, 2, 3]:Array (NoMethodError)
Is there such a written method for a union?
Array#union works fine in Ruby 2.6, but if it's not in Ruby 2.5 and you insist on having a method named union, the following worked like a champ for me in Ruby 2.3.7:
[1,2,3].union [4,5,6] # => NoMethodError: undefined method `union' for [1, 2, 3]:Array
class Array
def union(other)
self | other
end
end
[1,2,3].union [4,5,6] # => [1, 2, 3, 4, 5, 6]
To get functionality comparable to 2.6's Array#union documented behavior in earlier versions of Ruby:
class Array
def union(*others)
others.inject(self, &:|)
end
end
[1,2].union [3,4], [5] # => [1, 2, 3, 4, 5]
[10,11].union # => [10, 11]
There's no exact equivalent for Array#|, even in Ruby 2.6.
Array#union is implemented in array.c#rb_ary_union_multi while Array#| is implemented in array.c#rb_ary_or.
They both use rb_ary_union under the hood for small arrays (less than 16 elements) and rb_ary_union_hash for larger arrays but rb_ary_union_multi accepts more than 2 arguments:
a = [1, 2, 3]
b = [3, 4, 5]
c = [4, 5, 6]
a.union(b, c)
# => [1, 2, 3, 4, 5, 6]
a.|(b, c)
# ArgumentError (wrong number of arguments (given 2, expected 1))
I'm a bit puzzled about the way that Julia 1.0.3 treats global variables. Is there a way to use !push to update a global array?
While playing in the REPL, I want to update a global variable, then push! the result to a global array to store it.
var = [1]
res = []
for i in 1:5
global var
global res
push!(var,i)
print(string(var,"\n"))
push!(res,var)
end
However, the values stored in res are as follows:
[1, 1, 2, 3, 4, 5]
[1, 1, 2, 3, 4, 5]
[1, 1, 2, 3, 4, 5]
[1, 1, 2, 3, 4, 5]
[1, 1, 2, 3, 4, 5]
Whereas I would expect this:
[1, 1]
[1, 1, 2]
[1, 1, 2, 3]
[1, 1, 2, 3, 4]
[1, 1, 2, 3, 4, 5]
Particularly puzzling since behaviour seems as expected with variables, instead of arrays:
var = 1
res = []
for i in 1:5
global var
global res
var = var + i
print(string(var,"\n"))
push!(res, var)
end
Which gives expected result:
2
4
7
11
16
I am clearly missing something.
You're pushing the same var array to every spot in the res array. For example:
julia> var = [1]
1-element Array{Int64,1}:
1
julia> res = [var, var]
2-element Array{Array{Int64,1},1}:
[1]
[1]
julia> var[1] = 2
2
julia> res
2-element Array{Array{Int64,1},1}:
[2]
[2]
Both elements in the res array are var itself. So if you modify var (with push! or indexed assignment or somesuch), then no matter how you access it you'll see those modifications.
This doesn't occur with numbers because you cannot modify numbers themselves. You can change which number is stored in an array, but you cannot change the number 1 to represent 2 everywhere that 1 had previously been used — that's the equivalent of what's happening here.
To fix this, you'll often want to just create your var array inside the for loop (instead of outside it). But in this case, since you're iteratively adding things to var and want to save that intermediate state, you can use copy:
julia> for i in 1:5
global var
global res
push!(var,i)
print(string(var,"\n"))
push!(res,copy(var))
end
Any[1]
Any[1, 2]
Any[1, 2, 3]
Any[1, 2, 3, 4]
Any[1, 2, 3, 4, 5]
julia> res
5-element Array{Any,1}:
Any[1]
Any[1, 2]
Any[1, 2, 3]
Any[1, 2, 3, 4]
Any[1, 2, 3, 4, 5]
list = [1,2,3,4,5]
print(list)
for each in list:
list[each] = 4
print(list)
And I get the result:
[1, 4, 3, 4, 4]
Line 4 seems to be setting "each" to 4 somehow...but I have no idea how. It's SUPPOSED to change the value at the current iterator to 4., which it also does at list[4].
Edit:
Wait wait wait, okay, 'each' is literally coming from the value inside the list? That's the only logical way this any sense, now that I think about it.
This will work better.
list = [1,2,3,4,5]
for each in range(len(list)):
list[each] = 4
print(list)
The problem you are running into is that your loop goes over the numbers from 1 - 5, but the index of the list starts at zero.
Adding a zero element to your list, or decrementing the each value by one in the loop makes your code work. But this way of doing it is flawed as you are depending on the content of the list to be in order and represent the positions.
list = [0,1,2,3,4,5] # zero added here.
for each in list:
list[each] = 4
print(list)
Your loop is actually doing this.
Loop 1: -> [1, 2, 3, 4, 5]
^
position 1 = 4.
Output: -> [1, 4, 3, 4, 5]
Loop 2: -> [1, 4, 3, 4, 5]
^
position 4 = 4.
Output: -> [1, 4, 3, 4, 4]
Loop 3: -> [1, 4, 3, 4, 4]
^
position 3 = 4. (it is already 4)
Output: -> [1, 4, 3, 4, 4]
Loop 4: -> [1, 4, 3, 4, 4]
^
position 4 = 4. (it is already 4)
Output: -> [1, 4, 3, 4, 4]
Loop 5: -> [1, 4, 3, 4, 4]
^
position 4 = 4. (it is already 4)
Output: -> [1, 4, 3, 4, 4]
Better use enumerate(), so you can skip the range(len()):
some_list = [1,2,3,4,5]
for i, item in enumerate(some_list):
some_list[i] = 4
print(some_list)
[4, 4, 4, 4, 4]
This will change each item in some_list to 4 by its index.
Why your way doesn't work
The thinking error you probably make it that the first item in a list has index 0, not 1 :)
"doing it your way" would then be:
some_list = [1,2,3,4,5]
print(some_list)
for each in some_list:
some_list[each-1] = 4
print(some_list)
[1, 2, 3, 4, 5]
[4, 4, 4, 4, 4]
EDIT
Another way to show what #JensB is explaining is to run the code below. It is exactly showing what happens in each of the iterations:
some_list = [1,2,3,4,5]
print(some_list)
for each in some_list:
some_list[each] = 4
print("some_list["+str(each)+"] = 4")
print(some_list)
[1, 2, 3, 4, 5]
some_list[1] = 4
[1, 4, 3, 4, 5]
some_list[4] = 4
[1, 4, 3, 4, 4]
some_list[3] = 4
[1, 4, 3, 4, 4]
some_list[4] = 4
[1, 4, 3, 4, 4]
some_list[4] = 4
[1, 4, 3, 4, 4]
When iterating over a list, you get the actual items, not the indexes (since the indexes are useless more often than not).
Actually, if you only need to iterate over the indexes, you could do it like this:
for i in range(len(your_list))
But to actually replace all items in the list with a single one, you could simply create a new one:
your_list = [4] * len(your_list)
Or if you prefer modifying the existing list:
your_list[:] = [4] * len(your_list)
Also, you should not name any variable list. This shadows the builtin list() function which is quite useful e.g. if you want to turn an iterable in a list (with list being shadowed you'd have to use [x for x in iterable] instead of list(iterable)).