I am a groovy newbie. Maybe this is a piece of cake, but I want to overload the + operator for arrays/lists to code like this
def a= [1,1,1]
def b= [2,2,2]
assert [3,3,3] == a + b
I wouldn't recommend globally overriding well-established behaviors. But, if you insist, this will do as you ask:
ArrayList.metaClass.plus << {Collection b ->
[delegate, b].transpose().collect{x, y -> x+y}
}
A more localized alternative would be to use a category:
class PlusCategory{
public static Collection plus(Collection a, Collection b){
[a, b].transpose().collect{x, y -> x+y}
}
}
use (PlusCategory){
assert [3, 3, 3] == [1, 1, 1] + [2, 2, 2]
}
However, I would probably create a generic zipWith method (as in functional programming), allowing one to easily specify different behaviors...
Collection.metaClass.zipWith = {Collection b, Closure c ->
[delegate, b].transpose().collect(c)
}
assert [3, 3, 3] == [1, 1, 1].zipWith([2, 2, 2]){a, b -> a+b}
assert [2, 2, 2] == [1, 1, 1].zipWith([2, 2, 2]){a, b -> a*b}
Related
I'm trying to model a satisfaction problem with MiniZinc but I'm stuck at coding this constraint:
Given two arrays A and B of equal length, enforce that A is a permutation of B
In other words, I'm looking for a constraint that enforces [1,2,2]=[1,2,2] and also [1,2,2]=[2,2,1]. Informally, A and B have to be equal. The arrays are both defined on the same set of integers, in particular the set 1..n-1, for some n. Values in both A and B can be repeated (see example).
Is there such a global constraint in MiniZinc? Thank you.
Here is the predicate I tend to use for these cases. It requires an extra array (p) which contains the permutations from array a to array b.
/*
Enforce that a is a permutation of b with the permutation
array p.
*/
predicate permutation3(array[int] of var int: a,
array[int] of var int: p,
array[int] of var int: b) =
forall(i in index_set(a)) (
b[i] = a[p[i]]
)
/\
all_different(p)
;
A simple model using this:
include "globals.mzn";
int: n = 3;
array[1..n] of var 1..2: x;
array[1..n] of var 1..2: y;
array[1..n] of var 1..n: p;
/*
Enforce that array b is a permutation of array a with the permutation
array p.
*/
predicate permutation3(array[int] of var int: a,
array[int] of var int: p,
array[int] of var int: b) =
forall(i in index_set(a)) (
b[i] = a[p[i]]
)
/\
all_different(p)
;
solve satisfy;
constraint
x = [2,2,1] /\
permutation3(x,p,y)
;
output [
"x: \(x)\ny: \(y)\np: \(p)\n"
];
Output:
x: [2, 2, 1]
y: [1, 2, 2]
p: [3, 2, 1]
----------
x: [2, 2, 1]
y: [2, 1, 2]
p: [2, 3, 1]
----------
x: [2, 2, 1]
y: [1, 2, 2]
p: [3, 1, 2]
----------
x: [2, 2, 1]
y: [2, 1, 2]
p: [1, 3, 2]
----------
x: [2, 2, 1]
y: [2, 2, 1]
p: [2, 1, 3]
----------
x: [2, 2, 1]
y: [2, 2, 1]
p: [1, 2, 3]
----------
==========
There is an alternative formulation of this which don't requires the extra permutation p (it's defined inside the predicate):
predicate permutation3b(array[int] of var int: a,
array[int] of var int: b) =
let {
array[index_set(a)] of var index_set(a): p;
} in
forall(i in index_set(a)) (
b[i] = a[p[i]]
)
/\
all_different(p)
;
For the same problem, this will only output these 3 different solutions (the first model has more solutions since the the permutations differs).
x: [2, 2, 1]
y: [2, 2, 1]
----------
x: [2, 2, 1]
y: [2, 1, 2]
----------
x: [2, 2, 1]
y: [1, 2, 2]
----------
==========
Personally I tend to use the first version since I tend to want to output the permutation and like to have control over the variables.
In addition to the predicate shown by hakank, here are two other ways to express the same predicate
include "globals.mzn";
%
% Ensure that a and b are perumutations of each other by
% counting the number of occurences of each value in the
% domains of a and b,
%
predicate permutation_count(array[int] of var int: a,
array[int] of var int: b) =
let {
set of int: I = index_set(a),
constraint assert(I = index_set(b), "Index sets of a and b must match"),
set of int: domain = dom_array(a) intersect dom_array(b),
set of int: NValues = 1..card(domain),
array[NValues] of int: values = [ v | v in domain ],
array[NValues] of var 0..card(I): counts,
} in
global_cardinality_closed(a, values, counts) /\
global_cardinality_closed(b, values, counts);
%
% Ensure that a and b are permutations of each other by
% sorting each and constraining that to be the same.
%
predicate permutation_sort(array[int] of var int: a,
array[int] of var int: b) =
let {
set of int: I = index_set(a),
constraint assert(I = index_set(b), "Index sets of a and b must match"),
set of int: domain = dom_array(a) intersect dom_array(b),
array[I] of var domain: sorted_values,
} in
sorted_values = sort(a) /\
sorted_values = sort(b);
int: n = 3;
array[1..n] of var 1..2: x;
array[1..n] of var 1..2: y;
constraint permutation_count(x, y);
solve satisfy;
The first one counts the values in both input arrays, since in permutations the counts must be the same. The second variant uses the sorting constraint to sort both a and b to check that they are the same.
Which variant works best can vary between solvers, problems, and problem isntances. The counting solution may be problematic if the domains of the inputs are large, which is worth remembering.
So im pretty new to programming so sorry for my relatively very low understanding of python in general.
Say i have 2 lists, A and B.
If in some case i need to add numbers between 2 lists, each number adding to the number in the same position in the second list. Is there any simple way of doing so?
Eg. A = [1, 2, 3] B = [4, 5, 6]
so C = [1+4, 2+5, 3+6]
All I thought of so far being pretty tired is just adding the 2 but it just makes a list of items from A, followed by items from B
A = [1, 2, 3]
B = [4, 5, 6]
C = A + B
I'm trying to get C = [5, 7, 9] but it ends up being C = [1, 2, 3, 4, 5, 6]
I understand why this would be but being new to this i have no clue of how to do this properly
With that, you are concatenating the two lists, not performing element-wise addition. To do what you have to do, you have a few different options. This is my preferred method:
from operator import add
list(map(add, A, B))
A list comprehension would also work:
[sum(x) for x in zip(A, B)]
Using numpy will also work.
import numpy as np
A = [1, 2, 3]
B = [4, 5, 6]
C = (np.array(A) + np.array(B)).tolist()
Okay, so I have this function that I need to create and I think the code checker is somehow flawed and I tried manage it but my code still seems to fail
def reversecomp(L):
""" assumes L is a list of lists whose elements are ints
Mutates L such that it reverses its elements and also
reverses the order of the int elements in every element of L.
It does not return anything.
"""
if L == []:
return L
elif type(L) == int:
return L
else:
return reversecomp(L[1:]) + [reversecomp(L[0])]
def run_code(L):
return reversecomp(L)
print(L)
The question states that you need to mutate L. Your code must work when you do this:
L = [[0, 1, 2], [1, 2, 3], [3, 2, 1], [10, -10, 100]]
reversecomp(L)
print(L)
Test: run_code([[0, 1, 2], [1, 2, 3]])
Your output:
[[3, 2, 1], [2, 1, 0]]
Correct output:
[[3, 2, 1], [2, 1, 0]]
None
The spec says "It does not return anything"; your program does.
L is a list of lists of ints
Okay, so why are you checking type(L) == int when type(L) == list is always true, per the specification?
Mutates L
You're not mutating L at all; you're returning a new list. Mutating L means doing something like L[...] = xxx.
It does not return anything.
You shouldn't be using the return keyword at all in reversecomp.
Groovy allows unfolding lists in assignment, as in:
(x, y) = [1, 2]
So I assumed something similar would work in a for loop, as in:
list = [[1, 2], [2, 4], [3, 6]]
for ((elm1, elm2) in list) {...}
Which turns out to be a syntax error. Is this style not possible or is there some trick to it I'm missing?
I guess it won't work with the for loop (or I definitely don't know the syntax), however a two-argument closure can be used to iterate such a List, unfold the tuples:
def list = [[1, 2], [2, 4], [3, 6]]
assert list.collect { a, b -> a + b } == [3, 6, 9, ]
The following java code exists but I'm trying to convert it to groovy. Should I simply keep it as is w/ the System.arraycopy or does groovy have a nicer way to combine arrays like this?
byte[] combineArrays(foo, bar, start) {
def tmp = new byte[foo.length + bar.length]
System.arraycopy(foo, 0, tmp, 0, start)
System.arraycopy(bar, 0, tmp, start, bar.length)
System.arraycopy(foo, start, tmp, bar.length + start, foo.length - start)
tmp
}
Thank you
def a = [1, 2, 3]
def b = [4, 5, 6]
assert a.plus(b) == [1, 2, 3, 4, 5, 6]
assert a + b == [1, 2, 3, 4, 5, 6]
If you want to use an array:
def abc = [1,2,3,4] as Integer[] //Array
def abcList = abc as List
def xyz = [5,6,7,8] as Integer[] //Array
def xyzList = xyz as List
def combined = (abcList << xyzList).flatten()
Using Lists:
def abc = [1,2,3,4]
def xyz = [5,6,7,8]
def combined = (abc << xyz).flatten()
def a = [1, 2, 3]
def b = [4, 5, 6]
a.addAll(b)
println a
>> [1, 2, 3, 4, 5, 6]
The trick is the flatten() method, that combined nested arrays into one:
def a = [1, 2, 3]
def b = [4, 5, 6]
def combined = [a, b].flatten()
assert combined == [1, 2, 3, 4, 5, 6]
println(combined)
To remove null values you can use findAll() like this:
def a = null
def b = [4, 5, 6]
def combined = [a, b].flatten().findAll{it}
assert combined == [4, 5, 6]
println(combined)
I'd go with
byte[] combineArrays(foo, bar, int start) {
[*foo[0..<start], *bar, *foo[start..<foo.size()]]
}
It could be done like this:
def newCombine(foo,bar,start) {
([].add + foo[0..<start]+bar+foo[start..<foo.size()]).flatten()
}
It works for all kinds of arrays (byte[]) or lists
All the solutions above fails if an array is undefined:
def a = [1,2]
def b
assert a+b == [1, 2, null]
which is probably not what you want.
Either test if the array exists before adding:
def a = [1,2,3,4]
def b // null array
def c = [0,4,null,6]
def abc = []
[a,b,c].each{ if (it) abc += it }
assert abc == [1, 2, 3, 4, 0, 4, null, 6]
,or add all and then filter the output:
(a+b+c).findAll{ it != null }
(assuming here that null isn't a valid value in the original arrays, which implies that the first solution is a lot better, even if it may not look Groovy enough.)