On the operation of sort() - sorting

I would like to understand the workings of sort, in particular:
>>> a=[2,4,5,1]
>>> a
[2, 4, 5, 1]
>>> b=a
>>> b
[2, 4, 5, 1]
>>> b.sort()
>>> b
[1, 2, 4, 5]
>>> a
[1, 2, 4, 5]
Why when I apply sort() to the list "b" copied from "a", sort() also changes the list "a"?

You don't state what programming environment we're talking about. My best guess: b is a reference to a, so sorting b basically means that a is sorted implicitly.

typeof a "object"
typeof b "object"
In Javascript "object" is passed by reference.
So a and b are referring to same object. So sorting on "a" will have same effect on "b".

Ok, I've just resolve by my self...
>>> a=[2,4,5,1]
>>> b=a[:]
>>> b
[2, 4, 5, 1]
>>> b.sort()
>>> b
[1, 2, 4, 5]
>>> a
[2, 4, 5, 1]
Thanks

Related

Getting different output from manual vs. programmatic arrays

I’m getting some weird results implementing cyclic permutation on the children of a multidimensional array.
When I manually define the array e.g.
arr = [
[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]
]
the output is different from when I obtain that same array by calling a method that builds it.
I’ve compared the manual array to the generated version and they’re exactly the same (class and values, etc).
I tried writing the same algorithm in JS and encountered the same issue.
Any idea what might be going on?
def Build_array(child_arr, n)
#Creates larger array with arr as element, n times over. For example Build_array([1,2,3], 3) returns [[1,2,3], [1,2,3], [1,2,3]]
parent_arr = Array.new(4)
0.upto(n) do |i|
parent_arr[i] = child_arr
end
return parent_arr
end
def Cylce_child(arr, steps_tocycle)
# example: Cylce_child([1, 2, 3, 4, 5], 2) returns [4, 5, 1, 2, 3]
0.upto(steps_tocycle - 1) do |i|
x = arr.pop()
arr.unshift(x)
end
return arr
end
def Permute_array(parent_array, x, y, z)
#x, y, z = number of steps to cycle each child array
parent_array[0] = Cylce_child(parent_array[0], x)
parent_array[1] = Cylce_child(parent_array[1], y)
parent_array[2] = Cylce_child(parent_array[2], z)
return parent_array
end
arr = Build_array([1, 2, 3, 4, 5], 4)
# arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
puts "#{Permute_array(arr, 1, 2, 3)}"
# Line 34: When arr = Build_array([1, 2, 3, 4, 5], 4)
# Result (WRONG):
# [[5, 1, 2, 3, 4], [5, 1, 2, 3, 4], [5, 1, 2, 3, 4], [5, 1, 2, 3, 4]]
#
# Line 5: When arr = [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, # 2, 3, 4, 5]]
# Result (CORRECT):
# [[5, 1, 2, 3, 4], [4, 5, 1, 2, 3], [3, 4, 5, 1, 2], [1, 2, 3, 4, 5]]
#
The problem is in the way you build the array.
This line:
parent_arr[i] = child_arr
does not put in parent_arr[i] a copy of child_arr but a reference to it.
This means your initial array contains four references to the same child array. Later on, when the code changes parent_arr[0], it changes the same array that child_arr was referring to in the build method. And that array is also parent_arr[1] and parrent_arr[2] and so on.
A simple solution to the problem is to put in parent_arr[i] a copy of child_arr:
parent_arr[i] = Array.new(child_arr)
I see where the bug was. Added the clone method to line 8 so that it now reads:
parent_arr[i] = child_arr.clone
#Old: parent_arr[i] = child_arr
Thanks Robin, for pointing me in the right direction.
This is a fairly common mistake to make in Ruby since arrays do not contain objects per-se, but object references, which are effectively pointers to a dynamically allocated object, not the object itself.
That means this code:
Array.new(4, [ ])
Will yield an array containing four identical references to the same object, that object being the second argument.
To see what happens:
Array.new(4, [ ]).map(&:object_id)
# => => [70127689565700, 70127689565700, 70127689565700, 70127689565700]
Notice four identical object IDs. All the more obvious if you call uniq on that.
To fix this you must supply a block that yields a different object each time:
Array.new(4) { [ ] }.map(&:object_id)
# => => [70127689538260, 70127689538240, 70127689538220, 70127689538200]
Now adding to one element does not impact the others.
That being said, there's a lot of issues in your code that can be resolved by employing Ruby as it was intended (e.g. more "idiomatic" code):
def build_array(child_arr, n)
# Duplicate the object given each time to avoid referencing the same thing
# N times. Each `dup` object is independent.
Array.new(4) do
child_arr.dup
end
end
def cycle_child(arr, steps_tocycle)
# Ruby has a rotate method built-in
arr.rotate(steps_tocycle)
end
# Using varargs (*args) you can just loop over how many positions were given dynamically
def permute_array(parent_array, *args)
# Zip is great for working with two arrays in parallel, they get "zippered" together.
# Also map is what you use for transforming one array into another in a 1:1 mapping
args.zip(parent_array).map do |a, p|
# Rotate each element the right number of positions
cycle_child(p, -a)
end
end
arr = build_array([1, 2, 3, 4, 5], 4)
# => [[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]]
puts "#{permute_array(arr, 1, 2, 3)}"
# => [[5, 1, 2, 3, 4], [4, 5, 1, 2, 3], [3, 4, 5, 1, 2]]
A lot of these methods boil down to some very simple Ruby so they're not especially useful now, but this adapts the code as directly as possible for educational purposes.

Pop matching elements from array, then push them back

Say I have an array: [1, 2, 3, 4, 5].
Given another array ([2, 4], for example), I would like to have a new array (or the initial array modified, doesn't matter) that looks like: [1, 3, 5, 2, 4]. So selected elements are moved to the end of the array.
Pushing the elements back is quite straight-forward, but how do I pop specific elements from an array?
a = [1, 2, 3, 4, 5]
b = [2, 4]
(a - b) + (b & a)
#=> [1, 3, 5, 2, 4]
a - b is the elements in a but not in b, while b & a is the elements that are common in both arrays. There goes your expected result.
In case if elements in a are not uniq (as mentioned by eugen) and it's important to remove only one element from b you could do something like:
a = [1, 2, 3, 2, 4, 5, 4, 2]
b = [2, 4, 7]
p (b&a).unshift(a.map{|el|
b.include?(el) ? begin b = b -[el]; nil end : el
}.compact).flatten
#=> [1, 3, 2, 5, 4, 2, 2, 4]

Understanding the effect of arguments on .flatten method

The ruby doc does a great job of explaining what .flatten does without an argument. But I can't for the life of me understand what is happening when a 1 is passed to flatten
flatten(level) → new_ary
Returns a new array that is a one-dimensional flattening of self (recursively).That is, for every element that is an array, extract its elements into the new array.The optional level argument determines the level of recursion to flatten.
s = [ 1, 2, 3 ] #=> [1, 2, 3]
t = [ 4, 5, 6, [7, 8] ] #=> [4, 5, 6, [7, 8]]
a = [ s, t, 9, 10 ] #=> [[1, 2, 3], [4, 5, 6, [7, 8]], 9, 10]
a.flatten #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
a = [ 1, 2, [3, [4, 5] ] ]
a.flatten(1) #=> [1, 2, 3, [4, 5]]
By 'recursion' does it mean that the argument directly effects the number of actions '.flatten' performs to convert the multidimensional array to a regular singular array? Terms that a super-scrub can understand would be greatly appreciated here.
Thank you.
Basically, argument to flatten means how deep should go in attempts to flatten the structure.
a = [ 1, 2, [3, [4, 5] ] ]
# where
[ 1, 2, [3, [4, 5] ] ] # level 0 (original array)
[3, [4, 5] ] # level 1
[4, 5] # level 2
So, if you pass 1, it will go only one level deep and will treat level-2 array as a single element and will not recurse into it. So,
a.flatten(1) #=> [1, 2, 3, [4, 5]]
What #Sergio Tulentsev mentioned in his answer, are correct. But one more thing I would like to add here -
if you don't supply any argument, then flattening will be happened recursively, in all nested level. That is a.flatten will give [1, 2, 3, 4, 5].
Don't think a.flatten is same as a.flatten(0). No, they work differently. If you pass nested level number as 0,1,2, then flattening will be happened as you asked the method to do. But If you don't pass any argument, the method will work, as it is designed to do, i.e it will create a single level array, by breaking all the deeper nested one also.
a = [ 1, 2, [3, [4, [5,[6]]] ] ]
# see no nested level is here, all are flattened.
a.flatten # => [1, 2, 3, 4, 5, 6]

How can you "explode" an array in Ruby?

I'd like to "explode" an array in Ruby in order to do a fast variable assignment i.e.
a, b = ['first_var', 'second_var']
Is this possible? I've looked through the array docs and can't find anything that seems to offer this but it seems Rubyish...
This works as you would expect. Note that you can use * to slurp up extra right hand side elements, whereas extra elements on the left hand side will be set to nil:
>> range = *1..10 #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> a, b = range #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> [a, b] #=> [1, 2]
>> a, *b = range #=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>> b #=> [2, 3, 4, 5, 6, 7, 8, 9, 10]
>> a, b, c = 1,2 #=> [1, 2]
>> c #=> nil

"Pyramidizing" an array/list (in Ruby, but general solutions could probably be implemented)

I'm not sure what the best word to use here. By "pyramidizing", I mean:
[1,2,3,4].pyramidize # => [1,1,1,1,2,2,2,3,3,4]
["a","b","c","d"].pyramidize # => ["a","a","a","a","b","b","b","c","c","d"]
To represent visually, it could be thought of as:
[ 1,1,1,1,
2,2,2,
3,3,
4 ]
Is there a way to do this that maximizes elegance? A most ruby-like way?
I came across the "need" to do this in a project of mine. After thinking about it, I gave up and decided to work around the problem in an ugly way. I was wondering if there was a pretty way to do this. So far, to do it directly, I've ended up making a separate array for each index and stretching out each array the appropriate length and combining them together. But I don't know how to do this so it looks pretty; my solution is pretty ugly.
Added code golf tag because any solution in one line would probably make my day, but it doesn't have to be.
It doesn't really matter if your solution makes the first index the "base" of the pyramid, or the last index, because I could just reverse the array before running it.
Requires the new iterator fanciness in Ruby 1.9.
class Array
def pyramidize
reverse.map.with_index do |object, index|
[object] * (index + 1)
end.flatten.reverse
end
end
[1,2,3,4].pyramidize
=> [1, 1, 1, 1, 2, 2, 2, 3, 3, 4]
["a","b","c","d"].pyramidize
=> ["a", "a", "a", "a", "b", "b", "b", "c", "c", "d"]
irb(main):001:0> [2,1,3,5].flat_map.with_index{|i,j|[i]*(j+1)}
=> [2, 1, 1, 3, 3, 3, 5, 5, 5, 5]
irb(main):002:0> [1,2,3,4].flat_map{|i|[i]*i}
=> [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
I'm not sure if you want to use the value of the list or the index to determine how much the list should repeat, but a simple solution in python that can probably transfer to ruby easily:
>>> import operator
>>> input = range(6)
>>> reduce(operator.add, [[i]*idx for idx, i in enumerate(input)])
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5]
Update
Oh and to invert the counts:
>>> import operator
>>> input = range(1, 6)
>>> reduce(operator.add, [[i]*(max(input) - idx) for idx, i in enumerate(input)])
[1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5]
And of course you reversed the list in one of your examples:
>>> import operator
>>> input = range(1, 6)
>>> reduce(operator.add, [[i]*(max(input) - idx) for idx, i in enumerate(input)])[::-1]
[ 5,
4, 4,
3, 3, 3,
2, 2, 2, 2,
1, 1, 1, 1, 1]
FWIW, this is a mathy way of doing it:
>>> A = [1, 2, 3, 4]
>>> [ A[int((sqrt(8*k+1)-1) / 2)] for k in range(len(A)*(len(A)+1) / 2) ]
[1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
Admittedly, the use of sqrt is pretty ugly.
Here is another way to do it in Python
>>> A=[1,2,3,4]
>>> [y for i,x in enumerate(A) for y in [x]*(len(A)-i)]
[1, 1, 1, 1, 2, 2, 2, 3, 3, 4]
But it's nicer not to create all those temporary lists
>>> from itertools import repeat
>>> [y for i,x in enumerate(A) for y in repeat(x, len(A)-i)]
[1, 1, 1, 1, 2, 2, 2, 3, 3, 4]

Resources