I realize there is support for #each
Book.findAll().each(){ book->
println ">>> ${book}"
}
and there's even support for #inject
def sentence = m.inject('Message: ') { s, k, v ->
s += "${k == 'likes' ? 'loves' : k} $v "
}
Is there support for #map for Groovy out of the box (without any special libraries like Functional Java)?
def list = [1,2,3,4].map{ num->
num + 1
}
assert list == [2,3,4,5]
You want collect.
groovy:000> [1,2,3,4].collect { num -> num + 1 }
===> [2, 3, 4, 5]
I hope that helps.
You can use collect, as in
[1, 2, 3, 4].collect { it + 1 }
For the case where you're calling a method directly on each object in the collection there's a shorter syntax using the spread-dot operator:
[1, 2, 3, 4]*.plus 1
(using a method Groovy adds to java.lang.Integer to implement the + operator)
This operator works even if the list contains nulls:
groovy:000> [1, 2, 3, null, 4]*.plus 1
===> [2, 3, 4, null, 5]
where with collect you'd have to check:
[1, 2, 3, null, 4].collect { it?.plus 1 }
Related
I use spock-genesis and would like to have an infinite lists generator parametrized with a list of values. A generated item should be a list that contains at most the list of parametrized values in random order.
Some invariants are:
def 'list generator'() {
expect:
xs.size() <= 3
xs.findAll({x -> x == 1}).size() <= 1
xs.findAll({x -> x == 2}).size() <= 1
xs.findAll({x -> x == 3}).size() <= 1
where:
xs << listGen([1, 2, 3])
}
I'm about to write own Generator implementation but there is chance I overthink something and it's possible to compose such generator with already existing spock-genesis units.
Try this
List listGen(List list) {
list.subsequences()
.collect { it.permutations() }
.inject([[]]) { result, subseq -> result + subseq }
}
The result of listGen([1, 2, 3]) will be:
[[], [1], [1, 2, 3], [3, 2, 1], [2, 1, 3], [3, 1, 2], [1, 3, 2], [2, 3, 1], [2], [3, 2], [2, 3], [2, 1], [1, 2], [3], [1, 3], [3, 1]]
Your test passes with this implementation.
UPD:
As per the OP clarifications below in the comments, they expect the permutations to be random, so here is the line of code that will do that using spock-genesis any:
where:
xs << Gen.any(listGen([1, 2, 3])).take(42).collect() // I assume 42 here should be random as well then
I'm not quite sure what you want, is just a list of every possible permutation of the list [1,2,3]? If so then this should be enough.
[1, 2, 3].permutations()
With #Dmitry Khamitov help I've come up with spock-genesis generator
package spock.genesis.generators.composites
import groovy.transform.CompileStatic
import spock.genesis.generators.Generator
import spock.genesis.generators.UnmodifiableIterator
import spock.genesis.generators.values.RandomElementGenerator
/** A lazy infinite {#code Generator} that returns a random subset of elements from a source Collection
* #warning O(n!) time complexity. Starts being too expensive with lists 10+ elements
* #param < E > the generated type
*/
#CompileStatic
class ListSubsetGenerator<E> extends Generator<List<E>> {
final RandomElementGenerator<List<E>> valueSource
ListSubsetGenerator(Collection<E> source) {
this.valueSource = new RandomElementGenerator<>(getListsSource(source))
}
private List<List<E>> getListsSource(Collection<E> source) {
source.toList().subsequences()
.collect { it.permutations() }
.inject([[]]) { result, subseq ->
result.addAll(subseq)
result
} as List<List<E>>
}
#Override
UnmodifiableIterator<List<E>> iterator() {
new UnmodifiableIterator<List<E>>() {
private final Iterator<List<E>> source = valueSource.iterator()
#Override
boolean hasNext() {
source.hasNext()
}
#Override
List<E> next() {
source.next()
}
}
}
#Override
Generator<List<E>> seed(Long seed) {
super.seed(seed)
valueSource.seed(seed)
this
}
}
Here are some tests:
class ListSubsetGeneratorTest extends Specification {
#Iterations(100)
def 'test invariants'() {
expect:
xs.size() <= 3
xs.findAll({x -> x == 1}).size() <= 1
xs.findAll({x -> x == 2}).size() <= 1
xs.findAll({x -> x == 3}).size() <= 1
xs.every { [1, 2, 3].contains(it) }
where:
xs << new ListSubsetGenerator([1, 2, 3])
}
def 'setting seed produces the same sequences for different generators'() {
given:
def elements = ['a', 'b', 'c', 'd']
def xs = new ListSubsetGenerator(elements).seed(seed).take(100).realized
def ys = new ListSubsetGenerator(elements).seed(seed).take(100).realized
expect:
xs == ys
where:
seed << [Long.MIN_VALUE, 100, Long.MAX_VALUE]
}
}
Have there any way to split a list in dart based on a condition like following:
[1, 2, 3, 4, 5, 6, 7, 8] (A sample list)
After splitting it based on i % 2 == 0 condition,
it would generate the following two lists:
1) [1, 3, 5, 7]
2) [2, 4, 6, 8]
I know I can simply write a loop to go through all the elements and check the condition to create the two sublists. But have there any shorter functional way in dart?
Thanks in advance!
If you want to do this a lot it could be a good idea to create an extension method in your project which does what you want. I have come up with the following design which should work in a generic and efficient way:
void main() {
final s_list = [1, 2, 3, 4, 5, 6, 7, 8];
final match = s_list.splitMatch((element) => element % 2 == 0);
print(match.matched); // [2, 4, 6, 8]
print(match.unmatched); // [1, 3, 5, 7]
}
extension SplitMatch<T> on List<T> {
ListMatch<T> splitMatch(bool Function(T element) matchFunction) {
final listMatch = ListMatch<T>();
for (final element in this) {
if (matchFunction(element)) {
listMatch.matched.add(element);
} else {
listMatch.unmatched.add(element);
}
}
return listMatch;
}
}
class ListMatch<T> {
List<T> matched = <T>[];
List<T> unmatched = <T>[];
}
A quick solution:
var s_list = [1, 2, 3, 4, 5, 6, 7, 8];
s_list.where( (el) => el % 2 == 0 ).toList();
s_list.where( (el) => el % 2 != 0 ).toList();
Hello I am working with some lists I have the following list:
a = [1,2,3,4,5,6]
I would like to get the these two lists from a:
b = [2,3,4,5,6]
c = [1,2,3,4,5]
I would like to get the firt one removing the first element of a and the second one removing the last element of a, I tried:
b = a
c = a
b.pop(0)
c.pop(len(a)-1)
print(b)
print(c)
print(a)
However the output is:
[2, 3, 4, 5]
[2, 3, 4, 5]
[2, 3, 4, 5]
that is affecting my fist list, I am not sure about what I am doing, I would like to appreciate support with this.
You should not modify the original list - it's simpler than you think, just slice the input list passing the right indexes. Try this:
a = [1, 2, 3, 4, 5, 6]
b = a[1:]
c = a[:-1]
a
=> [1, 2, 3, 4, 5, 6]
b
=> [2, 3, 4, 5, 6]
c
=> [1, 2, 3, 4, 5]
I think slicing would be ok:
b =a[1:];
c =a[:-1]
I have a nested sequence that I want to flatten into a single list of values.
Please try this general solution:
Write a recursive generator function involving a yield from
statement. For example:
from collections import Iterable
def flatten(items, ignore_types=(str, bytes)):
for x in items:
if isinstance(x, Iterable) and not isinstance(x, ignore_types):
yield from flatten(x, ignore_types)
else:
yield x
items = [1, 2, [3, 4, [5, 6], 7], 8]
# Produces 1 2 3 4 5 6 7 8
for x in flatten(items):
print(x)
I'd go with recursion but split in a balanced way.
def flatten(lst):
n = len(lst)
if n == 0:
return lst
elif n == 1:
item = lst[0]
try:
return flatten(list(item))
except TypeError:
return [item]
else:
k = n // 2
return flatten(lst[:k]) + flatten(lst[k:])
Demo
items = [1, 2, [3, 4, [5, 6], 7], 8]
flatten(items)
[1, 2, 3, 4, 5, 6, 7, 8]
I have a List like [0, 1, 2, 3, 4, 2, 1] and i want to print a warning message for each tuple of elements in this list that are equal. So given the list above i would like to do something like
[0, 1, 2, 3, 4, 2, 1].someMethodIDontKnow { Int num, List owner ->
if(owner.contains(num)) println "warning, multiple "+ num +" detected"
println it
}
I can of course save the list and then do it like that:
List<Int> numlist = [0, 1, 2, 3, 4, 2, 1]
numlist.each {
if (numList.contains(it)) println "warning, multiple "+ it +" detected"
println it
}
But that is not as concise as the code before, especially when ithappens in a row of other calls like that:
List somelist
//...
somelist
.findAll{...}
.intersect{...}
//check for some warnings here
.collect{...}
.unique{...}
I would like to avoid assigning the list to a variable if i can do it differently.
Is there maybe some collection method that slipped through my eyes?
How about this?
[0, 1, 2, 3, 4, 2, 1].groupBy().each { k, v ->
if (v.size() > 1) {
println "Warning: multiple $k detected"
println k
}
}