Ruby array iteration and mutation - ruby

I have an array of similar objects, with an attribute a which can have values b or c. The array can be considered as a collection of rows, where each pair of items in the array represent one row. I've just listed the values of attribute a for simplicity's sake,
Example:
array = [c, b, b, c, c, c, b]
# array[0], array[1] is one row (c, b)
# array[2], array[3] is another (b, c)
# ...
There can be no row of just (b, b), and if that is the case then one of the b values must be swapped for the closest c value in the array. If there are no more c values, then the array is valid as long as the b values are left at the end of the array.
The final row of the array can consist of just one value, i. e. (b, ).
Example:
array = [b, c, b, b, c, b, b, b, c, b, b, c, c]
# becomes
array = [b, c, b, c, b, b, b, b, c, b, b, c, c]
array = [b, c, b, c, b, c, b, b, b, b, b, c, c]
array = [b, c, b, c, b, c, b, c, b, b, b, b, c]
array = [b, c, b, c, b, c, b, c, b, c, b, b, b]
# rows: (b, c), (b, c), (b, c), (b, c), (b, c), (b, b,), (b, )
This is the solution I came up with, which I don't really like (because it's very imperative and verbose)
while true do
cand = nil
array.each_slice(2) do |item, nxt|
return if nxt.nil?
# pseudo-code: assume b? returns true for a == b
next unless item.b? && nxt.b?
cand = nxt
break
end
swap_cand = array.slice(array.index(cand), array.length).reject{ |item| item.popular? }.first
return if swap_cand.nil?
old_index, new_index = array.index(cand), array.index(swap_cand)
array[old_index], array[new_index] = array[new_index], array[old_index]
end
A problem I kept running into was that I couldn't mutate an array while iterating over it, necessitating two loops.
edit Cleaned up some of the break statements per the suggestions from #7stud.

Enumerable#chunk is well-suited for this problem.
Code
def valid?(arr, b)
arr.chunk { |e| e }
.map(&:last)[0..-2]
.select { |e| e.first == b }
.max_by(&:size)
.size <= 2
end
Example
b = 0
c = 1
valid?([c, b, b, c, b, b, b], b) #=> true
valid?([c, b, b, b, c, c, b], b) #=> false
Explanation
b = 0
c = 1
arr = [c, b, b, c, b, b, b]
#=> [1, 0, 0, 1, 0, 0, 0]
enum = arr.chunk { |e| e }
#=> #<Enumerator: #<Enumerator::Generator:0x0000010205aa70>:each>
enum.to_a # Let's examine the elements of `enum`
#=> [[1, [1]], [0, [0, 0]], [1, [1]], [0, [0, 0, 0]]]
a = enum.map(&:last)
#=> [[1], [0, 0], [1], [0, 0, 0]]
d = a[0..-2] # disregard last value, which may or may not be an array of `b`'s
#=> [[1], [0, 0], [1]]
e = d.select { |e| e.first == b }
#=> [[0, 0]]
f = e.max_by(&:size)
#=> [0, 0]
g = f.size
#=> 2
g <= 2
#=> true

Related

How do I apply an ordering in place?

I have an array, e.g. a = [a, b, c, d]. I also have an ordering indicating the indexes of this array, e.g. [2, 0, 3, 1]. Applying the ordering would result in [c, a, d, b]
Explanation:
a [a, b, c, d]
current_idx: [0, 1, 2, 3]
target_idx: [2, 0, 3, 1]
result: [c, a, d, b]
How do you apply the order of target_idx to a in place (without creating a new a)?
Is there a name for such a sorting algorithm? I did not find anything when searching for "applying order to array"

How to use "solve" while comparing two matrices in MAXIMA?

I want to do a simple thing:
M: matrix([a,b], [c,d]);
N: matrix([1,2], [3,4]);
solve(M = N, [a,b,c,d]);
but I get the result []. If I break the above into many constraints, like this:
M: matrix([a,b], [c,d]);
N: matrix([1,2],[3,4]);
c1: M[1,1] = N[1,1];
c2: M[1,2] = N[1,2];
c3: M[2,1] = N[2,1];
c4: M[2,2] = N[2,2];
solve([c1, c2, c3, c4], [M[1,1], M[1,2], M[2,1], M[2,2]]);
I get a good result [[a=1,b=2,c=3,d=4]]. But this method would be painful for big matrices. Is there some easier way to do this?
Converting matrixes to list can help
(%i1) M: matrix([a,b], [c,d])$
(%i2) N: matrix([1,2] [c,d])$
(%i3) f(M):= apply(join, args(M))$
(%i4) e: map("=", f(M), f(N));
(%o4) [a = 1, c = 3, b = 2, d = 4]
(%i5) solve(e, [a, b, c, d]);
(%o4) [a = 1, c = 3, b = 2, d = 4]

Ruby block taking array or multiple parameters

Today I was surprised to find ruby automatically find the values of an array given as a block parameter.
For example:
foo = "foo"
bar = "bar"
p foo.chars.zip(bar.chars).map { |pair| pair }.first #=> ["f", "b"]
p foo.chars.zip(bar.chars).map { |a, b| "#{a},#{b}" }.first #=> "f,b"
p foo.chars.zip(bar.chars).map { |a, b,c| "#{a},#{b},#{c}" }.first #=> "f,b,"
I would have expected the last two examples to give some sort of error.
Is this an example of a more general concept in ruby?
I don't think my wording at the start of my question is correct, what do I call what is happening here?
Ruby block are quirky like that.
The rule is like this, if a block takes more than one argument and it is yielded a single object that responds to to_ary then that object is expanded. This makes yielding an array versus yielding a tuple seem to behave the same way for blocks that take two or more arguments.
yield [a,b] versus yield a,b do differ though when the block takes one argument only or when the block takes a variable number of arguments.
Let me demonstrate both of that
def yield_tuple
yield 1, 2, 3
end
yield_tuple { |*a| p a }
yield_tuple { |a| p [a] }
yield_tuple { |a, b| p [a, b] }
yield_tuple { |a, b, c| p [a, b, c] }
yield_tuple { |a, b, c, d| p [a, b, c, d] }
prints
[1, 2, 3]
[1]
[1, 2]
[1, 2, 3]
[1, 2, 3, nil]
Whereas
def yield_array
yield [1,2,3]
end
yield_array { |*a| p a }
yield_array { |a| p [a] }
yield_array { |a, b| p [a, b] }
yield_array { |a, b, c| p [a, b, c] }
yield_array { |a, b, c, d| p [a, b, c, d] }
prints
[[1, 2, 3]]
[[1, 2, 3]]
[1, 2] # array expansion makes it look like a tuple
[1, 2, 3] # array expansion makes it look like a tuple
[1, 2, 3, nil] # array expansion makes it look like a tuple
And finally to show that everything in Ruby uses duck-typing
class A
def to_ary
[1,2,3]
end
end
def yield_arrayish
yield A.new
end
yield_arrayish { |*a| p a }
yield_arrayish { |a| p [a] }
yield_arrayish { |a, b| p [a, b] }
yield_arrayish { |a, b, c| p [a, b, c] }
yield_arrayish { |a, b, c, d| p [a, b, c, d] }
prints
[#<A:0x007fc3c2969190>]
[#<A:0x007fc3c2969050>]
[1, 2] # array expansion makes it look like a tuple
[1, 2, 3] # array expansion makes it look like a tuple
[1, 2, 3, nil] # array expansion makes it look like a tuple
PS, the same array expansion behavior applies for proc closures which behave like blocks, whereas lambda closures behave like methods.
Ruby's block mechanics have a quirk to them, that is if you're iterating over something that contains arrays you can expand them out into different variables:
[ %w[ a b ], %w[ c d ] ].each do |a, b|
puts 'a=%s b=%s' % [ a, b ]
end
This pattern is very useful when using Hash#each and you want to break out the key and value parts of the pair: each { |k,v| ... } is very common in Ruby code.
If your block takes more than one argument and the element being iterated is an array then it switches how the arguments are interpreted. You can always force-expand:
[ %w[ a b ], %w[ c d ] ].each do |(a, b)|
puts 'a=%s b=%s' % [ a, b ]
end
That's useful for cases where things are more complex:
[ %w[ a b ], %w[ c d ] ].each_with_index do |(a, b), i|
puts 'a=%s b=%s # %d' % [ a, b, i ]
end
Since in this case it's iterating over an array and another element that's tacked on, so each item is actually a tuple of the form %w[ a b ], 0 internally, which will be converted to an array if your block only accepts one argument.
This is much the same principle you can use when defining variables:
a, b = %w[ a b ]
a
# => 'a'
b
# => 'b'
That actually assigns independent values to a and b. Contrast with:
a, b = [ %w[ a b ] ]
a
# => [ 'a', 'b' ]
b
# => nil
I would have expected the last two examples to give some sort of error.
It does in fact work that way if you pass a proc from a method. Yielding to such a proc is much stricter – it checks its arity and doesn't attempt to convert an array argument to an argument list:
def m(a, b)
"#{a}-#{b}"
end
['a', 'b', 'c'].zip([0, 1, 2]).map(&method(:m))
#=> wrong number of arguments (given 1, expected 2) (ArgumentError)
This is because zip creates an array (of arrays) and map just yields each element, i.e.
yield ['a', 0]
yield ['b', 1]
yield ['c', 2]
each_with_index on the other hand works:
['a', 'b', 'c'].each_with_index.map(&method(:m))
#=> ["a-0", "b-1", "c-2"]
because it yields two separate values, the element and its index, i.e.
yield 'a', 0
yield 'b', 1
yield 'c', 2

Mathematica enumerate combinations

I need to enumerate combinations for 3 groups of values that I have. The groups are (a,b,c,d), (e,f,g,h), (i,j,k,l) for example. The total combinations are 4x4x4=64.
Has anyone an idea, how can I define the ascending numbering of these combinations?
I have written something in that form:
Do[Do[Do[x["formula is needed here"]=s[[i,j,k]],{k,1,4}],{j,1,4}],{i,1,4}]
I cannot find the formula for the numbering of the combinations. I have read something about "Generating the mth Lexicographical Element of a Mathematical Combination" but I am more lost than helped. x is supposed to take values 1,2,3,....,64.
Thank you for your suggestions!
if you need a "formula" for the 'nth' tuple it looks like this:
{ Floor[(# - 1)/16 ] + 1,
Floor[Mod[# - 1, 16]/4] + 1 ,
Floor[Mod[# - 1, 4] ] + 1 } & /# Range[64] ==
Tuples[Range[4], 3]
True
so then if you want say the 12'th combination of your sets you could do something like this:
({
Floor[(# - 1)/16] + 1,
Floor[Mod[# - 1, 16]/4 + 1] ,
Mod[# - 1, 4] + 1 } &#12);
{{a, b, c, d}[[%[[1]]]], {e, f, g, h}[[%[[2]]]], {i, j, k,
l}[[%[[3]]]]}
{a, g, l}
note that whatever you are doing it is almost always best to use the built in object oriented functions.
Tuples[{{a, b, c, d}, {e, f, g, h}, {i, j, k, l}}][[12]]
{a, g, l}
Edit: for completeness a generalization of the first expression:
listlen = 6;
nsamp = 4;
Table[Floor[Mod[# - 1, listlen^i]/listlen^(i - 1) + 1], {i, nsamp,
1, -1}] & /# Range[listlen^nsamp] ==
Tuples[Range[listlen], nsamp]
True
Tuples[{{a, b, c, d}, {e, f, g, h}, {i, j, k, l}}]

Set starting point for cycle()

Given this array: a = ["a", "b", "c"]
If I run a.cycle { |x| puts x } I get print, a, b, c, a, b, c,.. forever.
Is there a way to set the starting point so that it would begin with "b" or the second index like this: print, b, c, a, b, c, a,.. forever. ?
Use Array#rotate
a.rotate.cycle {|x| puts x}
Pass an argument to rotate to shift to whichever index you want.

Resources