getting from list without duplicates (Groovy) - groovy

I have the following list and code
def myList = [[id:8100-04, name:AAA, code:2281],
[id:8100-05, name:BBB, code:2102],
[id:8100-06, name:CCC, code:6089],
[id:8100-07, name:CCC, code:6089],
[id:8100-08, name:CCC, code:6089]]
//list is retrived but looks something like the above
def newList = myList.findAll {
(it.get("Name").equals("AAA") ||
it.get("Name").equals("BBB") ||
it.get("Name").equals("AFBO") ||
it.get("Name").equals("CCC")) }
def filteredListData = newList.collect { getListData(it.get("Id"), it.get("Name"),
it.get("Code")) }
I want to retrieve all of my newList and if there is a duplicate then retrieve the entry with the lowest id Index.
so from myList i am looking for the result to be:
[[id:8100-04, name:AAA, code:2281],
[id:8100-05, name:BBB, code:2102],
[id:8100-06, name:CCC, code:6089]]

You are almost there.
def myList = [
[id:"8100-04", name:"AAA", code:2281],
[id:"8100-05", name:"BBB", code:2102],
[id:"8100-06", name:"CCC", code:6089],
[id:"8100-07", name:"CCC", code:6089],
[id:"8100-08", name:"CCC", code:6089]
]
def newList = myList.findAll {
it.name in ["AAA", "BBB", "AFBO", "CCC"]
}
def map = [:]
newList.each{
if(!map.get(it.name))
map.put(it.name, it)
}
println map*.value
Output:
[
[id:8100-04, name:AAA, code:2281],
[id:8100-05, name:BBB, code:2102],
[id:8100-06, name:CCC, code:6089]
]

Here is the script which addresses:
Unsorted items, note that order is changed in myList below.
OP did not mention the criteria for duplicate. This considers duplicate based on name and code
def myList = [[id:'8100-07', name:'CCC', code:6089],
[id:'8100-04', name:'AAA', code:2281],
[id:'8100-05', name:'BBB', code:2102],
[id:'8100-06', name:'CCC', code:6089],
[id:'8100-08', name:'CCC', code:6089]]
def newList = myList.findAll {
it.get("name").equals("AAA") ||
it.get("name").equals("BBB") ||
it.get("name").equals("AFBO") ||
it.get("name").equals("CCC")
}
//Sort by order id, name and code fields
def criteria = { a,b -> a.id <=> b.id ?: a.name <=> b.name ?: a.code?: b.code }
//Group by name and code ; apply sort; get the first item; apply sort on final result
def result = newList.groupBy({it.name}, {it.code}).inject([]){li, k, v-> v.collect {key, value -> li << value.sort(criteria)[0]}; li}.sort(criteria)
println result
You can quickly try online Demo

Here is a more "functional style" solution. We group by name, this gives a list for each name. Then we sort each of these lists and take its first element.
def myList = [[id:'8100-04', name:'AAA', code:2281],
[id:'8100-05', name:'BBB', code:2102],
[id:'8100-07', name:'CCC', code:6089],
[id:'8100-06', name:'CCC', code:6089],
[id:'8100-08', name:'CCC', code:6089]]
def newList = myList.findAll {
it.name in ["AAA", "BBB", "AFBO", "CCC"]
}
def groups = newList.groupBy {it -> it.name}
def lowestIds = groups.collect({it.value.sort{it.id}[0]})
println lowestIds
Even simpler:
newList.sort{it.id}.unique{it.name}
println newList

Related

how to merge dictionaries of lists with unique key values

I have below dictionaries of lists:
dict1 = {'SourceName': ['PUICUI'], 'EventType': ['XYX'], 'TableName': ['XYX__ct'], 'KeyIndex': ['XYX', 'ZXX']}
dict2 = {'SourceName': ['PUICI2'], 'EventType': ['XYX'], 'TableName': ['ZXX__ct1']}
And my below piece of code is working just as expected.
def combineDictList(*args):
result = {}
for dic in args:
for key in (result.keys() | dic.keys()):
if key in dic:
result.setdefault(key, []).extend(dic[key])
return result
print(combineDictList(dict1, dict2))
which gives me
{'TableName': ['XYX__ct', 'ZXX__ct1'], 'SourceName': ['PUICUI', 'PUICI2'], 'KeyIndex': ['XYX', 'ZXX'], 'EventType': ['XYX', 'XYX']}
But my question is how to print the final result to have unique values, e.g. here EventType has same values.
So, in final result i would only expect the final result to be
{'TableName': ['XYX__ct', 'ZXX__ct1'], 'SourceName': ['PUICUI', 'PUICI2'], 'KeyIndex': ['XYX', 'ZXX'], 'EventType': ['XYX']}
Is there anyway I can achieve this?
Try this
def combineDictList(*args):
result = {}
for dic in args:
for key in (result.keys() | dic.keys()):
if key in dic:
result.setdefault(key, []).extend(dic[key])
result[key] = list(set(result[key]))
return result
print(combineDictList(dict1, dict2))
Use set
Ex:
dict1 = {'SourceName': ['PUICUI'], 'EventType': ['XYX'], 'TableName': ['XYX__ct'], 'KeyIndex': ['XYX', 'ZXX']}
dict2 = {'SourceName': ['PUICI2'], 'EventType': ['XYX'], 'TableName': ['ZXX__ct1']}
def combineDictList(*args):
result = {}
for dic in args:
for k, v in dic.items():
result.setdefault(k, set()).update(v)
# If you need values as list
# result = {k: list(v) for k, v in result.items()}
return result
print(combineDictList(dict1, dict2))
Output:
{'EventType': {'XYX'},
'KeyIndex': {'ZXX', 'XYX'},
'SourceName': {'PUICI2', 'PUICUI'},
'TableName': {'ZXX__ct1', 'XYX__ct'}}

Groovy create list of 2 maps from string

Hi i have this String which contains List of 2 strings. These 2 strings then contain 2 maps.
Example def listStr = '["{"isReal":true,"area":"a"}","{"isRefundable":false,"area":"b"}"]';
How can i get from this string list of 2 maps?
Result [{isReal=true},{isRefundable=false}]
JsonSlurper can do the job for you:
import groovy.json.JsonSlurper
JsonSlurper js = new JsonSlurper()
def listStr = '["{"isReal":true}","{"isRefundable":false}"]'
def res = []
listStr.eachMatch( /"(\{[^\{\}]+\})"/ ){ res << js.parseText( it[ 1 ] ) }
assert [[isReal:true], [isRefundable:false]] == res
If you want to have a map in the output, you can trasnform the res like:
Map map = res.collectEntries{ it }
assert [isReal:true, isRefundable:false] == map

Two lists - Append and exchange

I have this
def url = "http://myurl/".toURL().text
def root = new XmlSlurper().parseText(url)
def namn = root.data.'content-item'.'**'.findAll{ node-> node.name() == 'resourceURI' }*.text()
def mylist = []
namn.each{
mylist << it
}
println mylist
def namn2 = root.data.'content-item'.'**'.findAll{ node-> node.name() == 'relativePath' }*.text()
def mylist2 = []
namn2.each{
mylist2 << it
}
println mylist2
That will be the output of this:
[http://myurl/, http://myurl/]
[/Sixten/1.1.0.235/, /Sixten/1.1.0.331/]
I know want to Exchange it to be
[Sixten-1.1.0.235.nupkg, Sixten-1.1.0.331.nupkg]
and then appended to the first list so it would result like this
[http://myurl/Sixten-1.1.0.235.nupkg, http://myurl/Sixten-1.1.0.331.nupkg]
HOW?
You don't need to do the each to get the values into a list... You already have lists:
def myList = root.data.'content-item'
.'**'
.findAll{ node-> node.name() == 'resourceURI' }
*.text()
def myList2 = root.data.'content-item'
.'**'
.findAll{ node-> node.name() == 'relativePath' }
*.text()
Then, to manipulate myList2, you just need:
myList2 = myList2*.getAt(1..-2)*.replaceAll('/', '-')*.plus('.nupkg')
And to append the urls to the start just requires:
[myList,myList2].transpose().collect { a, b -> a + b }
How about this:
def myList = ['http://myurl/', 'http://myurl/']
def myList2 = ['/Sixten/1.1.0.235/', '/Sixten/1.1.0.331/']
myList2 = myList2.collect { list2Entry ->
list2Entry[1..-2].replaceAll('/', '-') + '.nupkg'
}
def lst = []
myList.eachWithIndex{ txt, idx ->
lst << txt + myList2[idx]
}
println lst
prints:
[http://myurl/Sixten-1.1.0.235.nupkg, http://myurl/Sixten-1.1.0.331.nupkg]
First, inside the collect the leading and trailing slashes are removed by removing the first and last char of the strings with [1..-2]. Then the slashes in the middle of the strings are replaced by minus with replaceAll and .nupkg is added with string concatenation.
Inside the eachWithIndex every string from myList is concatenated with the string inside myList2 at the same position and the resulting string is added to the newly created list lst.

Groovy pointer to list

As I'm totally new to Groovy I have this problem I don't know how to solve:
I wan't to get a new value from a list, which list is depending of the value of the input string:
Simplified Example:
class NewStringValue
{
def getValue (inpList)
{
def list1 = ["L1V1","L1V2","L1V3"];
def list2 = ["L2V1","L2V2","L2V3","L2V4"];
def worklist = Here is my problem, how do I get Worklist to point to the correct list according to the value in InpList, see calling ex. below?
def i = 0;
def j = worklist.size-1;
while (i<=j)
{
// some code.......
newValue = worklist[i];
}
return newValue;}
Example of calling above
value = getValue("list1")
You can use a map, and look up the values based on the key passed in:
class NewStringValue {
def getValue(inpList) {
def lookup = [
list1: ["L1V1","L1V2","L1V3"],
list2: ["L2V1","L2V2","L2V3","L2V4"]
]
def worklist = lookup[inpList]
def newValue = ''
worklist.each {
newValue += it
}
newValue
}
}
new NewStringValue().getValue('list2')

Create Map from existing Map in Groovy

I have a Map
[email:[hus#gmail.com, vin#gmail.com], jobTitle:[SE, SD], isLaptopRequired:[on, on], phone:[9908899876, 7765666543], name:[hus, Vin]]
for which i need to have a another Map like
[hus:[hus#gmail.com,SE,99087665343],vin:[vin#gmail.com,SE,7765666543]]
How can do it in Groovy?
You could do it like:
def map = [email:['hus#gmail.com', 'vin#gmail.com'], jobTitle:['SE', 'SD'], isLaptopRequired:['on', 'on'], phone:['9908899876', '7765666543'], name:['hus', 'Vin']]
def result = [:]
map.name.eachWithIndex { name, idx ->
result << [ (name): map.values()*.getAt( idx ) - name ]
}
assert result == [hus:['hus#gmail.com', 'SE', 'on', '9908899876'], Vin:['vin#gmail.com', 'SD', 'on', '7765666543']]
Or, you could also do:
def result = [map.name,map.findAll { it.key != 'name' }.values().toList().transpose()].transpose().collectEntries()
But this is just less code at the expense of both readability and resource usage ;-)
The most visual solution i have:
def map = [email:['hus#gmail.com', 'vin#gmail.com'], jobTitle:['SE', 'SD'], isLaptopRequired:['on', 'on'], phone:['9908899876', '7765666543'], name:['hus', 'Vin']]
def names = map.name
def emails = map.email
def jobTitles = map.jobTitle
def isLaptopRequireds = map.isLaptopRequired //sorry for the variable name
def phones = map.phone
def result = [:]
for(i in 0..names.size()-1) {
result << [(names[i]): [emails[i], jobTitles[i], isLaptopRequireds[i], phones[i]]]
}
assert result == [hus:['hus#gmail.com', 'SE', 'on', '9908899876'], Vin:['vin#gmail.com', 'SD', 'on', '7765666543']]
}

Resources