I want to collect all the elements in a specific array list under a specific index. Let's say I have this list:
def names = ["David", "Arthur", "Tommy", "Jacob"]
I want to print all the names under the index of 2, which in this case, will print "David, Arthur"
Now I can use a for loop quite easily with that or even groovy's eachWithIndex(). The problem is I don't want to run all over the elements because that's not efficient. Rather than that, I want to run until a specific point.
Is there any method in groovy which does that , because I didn't find one.
Thanks in advance!
Since you're starting at index 0, the take method is probably the simplest approach.
def names = ["David", "Arthur", "Tommy", "Jacob"]
assert ['David', 'Arthur'] == names.take(2)
Given the list
def names = ["David", "Arthur", "Tommy", "Jacob"]
you can use any of the options below:
assert [ "Tommy", "Jacob" ] == names[ 2..<4 ]
assert [ "Tommy", "Jacob" ] == names[ 2..-1 ]
assert [ "Tommy", "Jacob" ] == names.subList( 2, 4 )
assert [ "Tommy", "Jacob" ] == names.drop( 2 )
Note, that each of these methods create a new List instance, so if the memory considerations are of importance, it makes sense to skip the elements using e.g. eachWithIndex() method or alike
Using Ranges:
def names = ["David", "Arthur", "Tommy", "Jacob"]
def idx = 2
def sublist = names[0..idx-1]
sublist.each { n ->
println n
}
Using more syntactic sugar:
names[0..<idx]
Related
I have a question about iterating through lists.
Let's say i have list of maps with format
def listOfMaps = [ ["date":"2013/05/23", "id":"1"],
["date":"2013.05.23", "id":"2"],
["date":"2013-05-23", "id":"3"],
["date":"23/05/2013", "id":"4"] ]
Now i have a list of two patterns (in reality i have a lot more :D)
def patterns = [
/\d{4}\/\d{2}\/\d{2}/, //'yyyy/MM/dd'
/\d{4}\-\d{2}\-\d{2}/ //'yyyy-MM-dd'
]
I want to println dates only with the "yyyy/MM/dd" and "yyyy-MM-dd" format so i have to go through the lists
for (int i = 0; i < patterns.size(); i++) {
def findDates = listOfMaps.findAll{it.get("word") ==~ patterns[i] ?
dateList << it : "Nothing found"}
}
but i have a problem with this way. What if the list "listOfMaps" gonna be huge? It will take a lot of time to find all patters because this code will have to go through the whole list of patters and the same amount of time it will have to go through list of maps wich in case of huge lists might take a long while :). I tried with forEach inside the findAll clousure it does not work.
So my question is is there any way to go through the list of patterns inside the findAll clousure? For instance sth like this in pseudocode
def findDates = listOfMaps.findAll{it.get("word") ==~ for(){patterns[i]} ? : }
so in that case it goes only once through the listOfMaps list and it iterates through patterns(which always is way way way way smaller than listOfMaps).
I might have an idea to create a function that returns the instance of list, but i'm struggling to implement this :).
Thanks in advance for response.
You could do:
def listOfMaps = [ [date:"2013/05/23", id:"1"],
[date:"2013.05.23", id:"2"],
[date:"2013-05-23", id:"3"],
[date:"23/05/2013", id:"4"] ]
def patterns = [
/\d{4}\/\d{2}\/\d{2}/, //'yyyy/MM/dd'
/\d{4}\-\d{2}\-\d{2}/ //'yyyy-MM-dd'
]
def foundRecords = listOfMaps.findAll { m ->
patterns.find { p ->
m.date ==~ p
}
}
Does Groovy have a smart way to check if a list is sorted? Precondition is that Groovy actually knows how to sort the objects, e.g. a list of strings.
The way I do right now (with just some test values for this example) is to copy the list to a new list, then sort it and check that they are equal. Something like:
def possiblySorted = ["1", "2", "3"]
def sortedCopy = new ArrayList<>(possiblySorted)
sortedCopy.sort()
I use this in unit tests in several places so it would be nice with something like:
def possiblySorted = ["1", "2", "3"]
possiblySorted.isSorted()
Is there a good way like this to check if a list is sorted in Groovy, or which is the preffered way? I would almost expect Groovy to have something like this, since it is so smart with collections and iteration.
If you want to avoid doing an O(n*log(n)) operation to check if a list is sorted, you can iterate it just once and check if every item is less or equals than the next one:
def isSorted(list) {
list.size() < 2 || (1..<list.size()).every { list[it - 1] <= list[it] }
}
assert isSorted([])
assert isSorted([1])
assert isSorted([1, 2, 2, 3])
assert !isSorted([1, 2, 3, 2])
Why not just compare it to a sorted instance of the same list?
def possiblySorted = [ 4, 2, 1 ]
// Should fail
assert possiblySorted == possiblySorted.sort( false )
We pass false to the sort method, so it returns a new list rather than modifying the existing one
You could add a method like so:
List.metaClass.isSorted = { -> delegate == delegate.sort( false ) }
Then, you can do:
assert [ 1, 2, 3 ].isSorted()
assert ![ 1, 3, 2 ].isSorted()
I need to validate if my list of list has equally sized lists in python
myList1 = [ [1,1] , [1,1]] // This should pass. It has two lists.. both of length 2
myList2 = [ [1,1,1] , [1,1,1], [1,1,1]] // This should pass, It has three lists.. all of length 3
myList3 = [ [1,1] , [1,1], [1,1]] // This should pass, It has three lists.. all of length 2
myList4 = [ [1,1,] , [1,1,1], [1,1,1]] // This should FAIL. It has three list.. one of which is different that the other
I could write a loop to iterate over the list and check the size of each sub-list. Is there a more pythonic way to achieve the result.
all(len(i) == len(myList[0]) for i in myList)
To avoid incurring the overhead of len(myList[0]) for each item, you can store it in a variable
len_first = len(myList[0]) if myList else None
all(len(i) == len_first for i in myList)
If you also want to be able to see why they aren't all equal
from itertools import groupby
groupby(sorted(myList, key=len), key=len)
Will group the lists by the lengths so you can easily see the odd one out
You could try:
test = lambda x: len(set(map(len, x))) == 1
test(myList1) # True
test(myList4) # False
Basically, you get the length of each list and make a set from those lengths, if it contains a single element then each list has the same length
def equalSizes(*args):
"""
# This should pass. It has two lists.. both of length 2
>>> equalSizes([1,1] , [1,1])
True
# This should pass, It has three lists.. all of length 3
>>> equalSizes([1,1,1] , [1,1,1], [1,1,1])
True
# This should pass, It has three lists.. all of length 2
>>> equalSizes([1,1] , [1,1], [1,1])
True
# This should FAIL. It has three list.. one of which is different that the other
>>> equalSizes([1,1,] , [1,1,1], [1,1,1])
False
"""
len0 = len(args[0])
return all(len(x) == len0 for x in args[1:])
To test it save it to a file so.py and run it like this:
$ python -m doctest so.py -v
Trying:
equalSizes([1,1] , [1,1])
Expecting:
True
ok
Trying:
equalSizes([1,1,1] , [1,1,1], [1,1,1])
Expecting:
True
ok
Trying:
equalSizes([1,1] , [1,1], [1,1])
Expecting:
True
ok
Trying:
equalSizes([1,1,] , [1,1,1], [1,1,1])
Expecting:
False
ok
If you want a little more data in failure cases, you could do:
myList1 = [ [1,1] , [1,1]]
lens = set(itertools.imap(len, myList1))
return len(lens) == 1
# if you have lists of varying length, at least you can get stats about what the different lengths are
I'm working with a large list containing integers and I would like to do some pattern matching on them (like finding certain sequences). Regular expressions would be the perfect fit, except that they always seem to only handle lists of characters, a.k.a. strings. Is there any library (in any language) that can handle lists of an arbitrary type?
I'm aware that I could convert my integer list into a string and then do a normal regular expression search but that seems a bit wasteful and inelegant.
edit:
My requirements are fairly simple. No need for nested lists, no need for fancy character classes. Basically I'm just interested in occurrences of sequences that can get pretty complicated. (e.g. something like "[abc]{3,}.([ab]?[^a]{4,7})" etc. where a,b,c are integers). This should be possible to generalize over any type which can be checked for equality. For an enumerable type you could also get things like "[a-z]" to work.
Regular expressions match only strings, by definition.
Of course, in theory you could construct an equivalent grammar, say for lists of numbers. With new tokens like \e for even numbers, \o for odd numbers, \s for square numbers, \r for real numbers etc., so that
[1, 2, 3, 4, 5, 6]
would be matched by
^(\o\e)*$
or
[ln(3), math.pi, sqrt(-1)]
would be matched by
^\R*$
etc. Sounds like a fun project, but also like a very difficult one. And how this could be expanded to handle arbitrary lists, nested and all, is beyond me.
Some of the regex syntax generalize to generic sequences. Also, to be able to specify any object, strings is not the best medium for the expression themselves.
"Small" example in python:
def choice(*items):
return ('choice',[value(item) for item in items])
def seq(*items):
return ('seq',[value(item) for item in items])
def repeat(min,max,lazy,item):
return ('repeat',min,max,lazy,value(item))
def value(item):
if not isinstance(item,tuple):
return ('value',item)
return item
def compile(pattern):
ret = []
key = pattern[0]
if key == 'value':
ret.append(('literal',pattern[1]))
elif key == 'seq':
for subpattern in pattern[1]:
ret.extend(compile(subpattern))
elif key == 'choice':
jumps = []
n = len(pattern[1])
for i,subpattern in enumerate(pattern[1]):
if i < n-1:
pos = len(ret)
ret.append('placeholder for choice')
ret.extend(compile(subpattern))
jumps.append(len(ret))
ret.append('placeholder for jump')
ret[pos] = ('choice',len(ret)-pos)
else:
ret.extend(compile(subpattern))
for pos in jumps:
ret[pos] = ('jump', len(ret)-pos)
elif key == 'repeat':
min,max,lazy,subpattern = pattern[1:]
for _ in xrange(min):
ret.extend(compile(subpattern))
if max == -1:
if lazy:
pos = len(ret)
ret.append('placeholder for jump')
ret.extend(compile(subpattern))
ret[pos] = ('jump',len(ret)-pos)
ret.append(('choice',pos+1-len(ret)))
else:
pos = len(ret)
ret.append('placeholder for choice')
ret.extend(compile(subpattern))
ret.append(('jump',pos-len(ret)))
ret[pos] = ('choice',len(ret)-pos)
elif max > min:
if lazy:
jumps = []
for _ in xrange(min,max):
ret.append(('choice',2))
jumps.append(len(ret))
ret.append('placeholder for jump')
ret.extend(compile(subpattern))
for pos in jumps:
ret[pos] = ('jump', len(ret)-pos)
else:
choices = []
for _ in xrange(min,max):
choices.append(len(ret))
ret.append('placeholder for choice')
ret.extend(compile(subpattern))
ret.append(('drop,'))
for pos in choices:
ret[pos] = ('choice',len(ret)-pos)
return ret
def match(pattern,subject,start=0):
stack = []
pos = start
i = 0
while i < len(pattern):
instruction = pattern[i]
key = instruction[0]
if key == 'literal':
if pos < len(subject) and subject[pos] == instruction[1]:
i += 1
pos += 1
continue
elif key == 'jump':
i += instruction[1]
continue
elif key == 'choice':
stack.append((i+instruction[1],pos))
i += 1
continue
# fail
if not stack:
return None
i,pos = stack.pop()
return pos
def find(pattern,subject,start=0):
for pos1 in xrange(start,len(subject)+1):
pos2 = match(pattern,subject,pos1)
if pos2 is not None: return pos1,pos2
return None,None
def find_all(pattern,subject,start=0):
matches = []
pos1,pos2 = find(pattern,subject,start)
while pos1 is not None:
matches.append((pos1,pos2))
pos1,pos2 = find(pattern,subject,pos2)
return matches
# Timestamps: ([01][0-9]|2[0-3])[0-5][0-9]
pattern = compile(
seq(
choice(
seq(choice(0,1),choice(0,1,2,3,4,5,6,7,8,9)),
seq(2,choice(0,1,2,3)),
),
choice(0,1,2,3,4,5),
choice(0,1,2,3,4,5,6,7,8,9),
)
)
print find_all(pattern,[1,3,2,5,6,3,4,2,4,3,2,2,3,6,6,5,3,5,3,3,2,5,4,5])
# matches: (0,4): [1,3,2,5]; (10,14): [2,2,3,6]
A few points of improvement:
More constructs: classes with negation, ranges
Classes instead of tuples
If you really need a free grammar like in regular expressions, then you have to go a way as described in Tim's answer.
If you only have a fixed number of patterns to search for, then the easiest and fastest way is to write your own search/filter functions.
Interesting problem indeed.
Lateral thinking: download the .Net Framework Source code, lift the Regex source code and adapt it to work with integers rather than characters.
Just an idea.
Well, Erlang has pattern matching (of your type) built right in. I did something similar once in Ruby - a bit of probably not too well performing hackery, see http://radiospiel.org/0x16-its-a-bird
Clojure since version 1.9 has clojure.spec in the standard library, which can do exactly that and more. For example to describe a sequence of odd numbers that may end with one even number you'd write:
(require '[clojure.spec.alpha :as s])
(s/def ::odds-then-maybe-even (s/cat :odds (s/+ odd?)
:even (s/? even?)))
Then to get matching subsequences you'd do this:
(s/conform ::odds-then-maybe-even [1 3 5 100])
;;=> {:odds [1 3 5], :even 100}
(s/conform ::odds-then-maybe-even [1])
;;=> {:odds [1]}
And to find out why a sequence doesn't match your definition:
(s/explain ::odds-then-maybe-even [100])
;; In: [0] val: 100 fails spec: ::odds-then-maybe-even at: [:odds] predicate: odd?
See full documentation with examples at https://clojure.org/guides/spec
You can try pamatcher, it's a JavaScript library that generalize the notion of regular expressions for any sequence of items (of any type).
An example for "[abc]{3,}.([ab]?[^a]{4,7})" pattern matching, where a, b, c are integers:
var pamatcher = require('pamatcher');
var a = 10;
var b = 20;
var c = 30;
var matcher = pamatcher([
{ repeat:
{ or: [a, b, c] },
min: 3
},
() => true,
{ optional:
{ or: [a, b] }
},
{ repeat: (i) => i != a,
min: 4,
max: 7
}
]);
var input = [1, 4, 8, 44, 55];
var result = matcher.test(input);
if(result) {
console.log("Pattern matches!");
} else {
console.log("Pattern doesn't match.");
}
Note: I am the creator of this library.
I am trying to create a new list via a list comprehension but want those new values to be included in an existing list.
More specifically, I am try to create a string out of the date and will have some string formatting between the values ( a dash - ). The existing list will be a template if you will with the dash.
Here is what I have so far:
{Date, Time} = erlang:universaltime().
DateList = tuple_to_list(Date).
DateListString = [ integer_to_list(X) || X < DateList ].
DateListStringConcatenate = lists:flatten(DateListString).
The result should be something along
"20101121"
But, what I want is
"2010-11-21"
So I am thinking about the DateListString comprehension "comprehending" to an existing list with "-" after the first and second element.
Any suggestions accompanied with concrete code samples much appreciated.
1> {{Y,M,D},_} = erlang:universaltime().
{{2010,11,21},{16,42,56}}
2> lists:flatten(io_lib:format("~p-~p-~p", [Y,M,D])).
"2010-11-21"
If you really want it in a list comprehension then you could do the following:
{Date, Time} = erlang:universaltime().
DateList = tuple_to_list(Date).
DateListString = [ [$- | integer_to_list(X)] || X <- DateList ].
[_ | DateListStringConcatenate] = lists:flatten(DateListString).
Roberto's is a better/more efficient solution to this but in case you wondered how you might do it with a list comprehension this would be one way.
This is a possible solution, but I feel that it is not an elegant one. Also, it does not use list comprehension.
1> {Date, Time} = erlang:universaltime().
{{2010,11,21},{14,51,23}}
2> DateList = tuple_to_list(Date).
[2010,11,21]
3> DateListString = lists:zipwith(fun(X,Y) -> integer_to_list(X) ++ Y end, DateList, ["-","-",""]).
["2010-","11-","21"]
4> DateListStringConcatenate = lists:flatten(DateListString).
"2010-11-21"