How to change variables with in a string into a Map - groovy

I have let's say 100 variables in a string , my requirement is to automatically create a Map out of the string:
String str = "$$test$$ $$test2$$ $$test$$ $$test3$$"
Expected Result:
["test":test, "test2":test2, "test3":test3];
EDIT (for dsharew)
This is the last version of my code
def list = queryText.findAll(/\$\$(.*?)\$\$/)
def map = [:]
list.each{
log.debug(it)
it = it.replace("\$\$", "")
log.debug(it)
map.putAt(it, it)
}
log.debug(list)
log.debug(map)
queryText = queryText.replaceAll(/\$\$(.*?)\$\$/) { k -> map[k[1]] ?: k[0] }
log.debug(queryText)
And the logs print the following result:
$$test$$
test
$$test2$$
test2
$$test$$
test
$$test3$$
test3
[$$test$$, $$test2$$, $$test$$, $$test3$$]
{test=test, test2=test2, test3=test3}
test test2 test test3

This should do what you want:
def queryText = "\$\$test\$\$ \$\$test2\$\$ \$\$test\$\$ \$\$test3\$\$"
toMap(queryText.findAll(/\$\$(.*?)\$\$/));
def toMap(list){
def map = [:]
list.each{
it = it.replace("\$\$", "")
map.putAt(it, it)
};
println map;
return map;
}

Following #dsharew answer, I've reduced it a little bit more:
​def queryText = "\$\$test\$\$ \$\$test2\$\$ \$\$test\$\$ \$\$test3\$\$"
def resultMap = queryText
.findAll(/\$\$(.*?)\$\$/)
.collectEntries { String next ->
[next.replace("\$\$", "")] * 2
}
collectEntries can be used to return a map from a collection if it returns a map or a tuple for every entry in the collection.
If you multiply a list by n, you are creating a bigger list with n times its content
BTW cool problem!

This is what I came up with
String str = '$$test$$ $$test2$$ $$test$$ $$test3$$'
str.replaceAll('\\$\\$', '').split(' ').collectEntries { [(it):it] }

Related

How can i get my list in correct order

I have almost got it right but my order will be like this
1.1.0.98
1.1.0.65
1.1.0.134
1.1.0.103
so it seems that when a third number is on it goes below the second.
code
def url = "http://mylink/".toURL().text
def root = new XmlSlurper().parseText(url)
def mylist = []
root.data.'content-item'.each{node ->
mylist << node.resourceURI.text() + node.relativePath.text().getAt(1..-2).replaceAll('/', '-').plus('.nupkg')
}
def result = []
mylist .reverseEach {
result << it
}
result
No idea what you're asking, but you can make your code a lot simpler...
This should work:
def result = root.data.'content-item'.collect { node ->
node.resourceURI.text() +
node.relativePath.text()[1..-2].replaceAll('/', '-') +
'.nupkg'
}.reverse()
no need for myList or reverseEach

Grails convert String to Map with comma in string values

I want convert string to Map in grails. I already have a function of string to map conversion. Heres the code,
static def StringToMap(String reportValues){
Map result=[:]
result=reportValues.replace('[','').replace(']','').replace(' ','').split(',').inject([:]){map,token ->
List tokenizeStr=token.split(':');
tokenizeStr.size()>1?tokenizeStr?.with {map[it[0]?.toString()?.trim()]=it[1]?.toString()?.trim()}:tokenizeStr?.with {map[it[0]?.toString()?.trim()]=''}
map
}
return result
}
But, I have String with comma in the values, so the above function doesn't work for me. Heres my String
[program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]
my function returns ABC only. not ABC, INC. I googled about it but couldnt find any concrete help.
Generally speaking, if I have to convert a Stringified Map to a Map object I try to make use of Eval.me. Your example String though isn't quite right to do so, if you had the following it would "just work":
// Note I have added '' around the values.
​String a = "[program_type:'', subsidiary_code:'', groupName:'', termination_date:'', effective_date:'', subsidiary_name:'ABC']"
Map b = Eval.me(a)​
// returns b = [program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC]
If you have control of the String then if you can create it following this kind of pattern, it would be the easiest solution I suspect.
In case it is not possible to change the input parameter, this might be a not so clean and not so short option. It relies on the colon instead of comma values.
​String reportValues = "[program_type:, subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]"
reportValues = reportValues[1..-2]
def m = reportValues.split(":")
def map = [:]
def length = m.size()
m.eachWithIndex { v, i ->
if(i != 0) {
List l = m[i].split(",")
if (i == length-1) {
map.put(m[i-1].split(",")[-1], l.join(","))
} else {
map.put(m[i-1].split(",")[-1], l[0..-2].join(","))
}
}
}
map.each {key, value -> println "key: " + key + " value: " + value}
BTW: Only use eval on trusted input, AFAIK it executes everything.
You could try messing around with this bit of code:
String tempString = "[program_type:11, 'aa':'bb', subsidiary_code:, groupName:, termination_date:, effective_date:, subsidiary_name:ABC, INC]"
List StringasList = tempString.tokenize('[],')
def finalMap=[:]
StringasList?.each { e->
def f = e?.split(':')
finalMap."${f[0]}"= f.size()>1 ? f[1] : null
}
println """-- tempString: ${tempString.getClass()} StringasList: ${StringasList.getClass()}
finalMap: ${finalMap.getClass()} \n Results\n finalMap ${finalMap}
"""
Above produces:
-- tempString: class java.lang.String StringasList: class java.util.ArrayList
finalMap: class java.util.LinkedHashMap
Results
finalMap [program_type:11, 'aa':'bb', subsidiary_code:null, groupName:null, termination_date:null, effective_date:null, subsidiary_name:ABC, INC:null]
It tokenizes the String then converts ArrayList by iterating through the list and passing each one again split against : into a map. It also has to check to ensure the size is greater than 1 otherwise it will break on f[1]

Incomprehensible technical interview

This was a question asked in a recent programming interview.
Given a string "str" and pair of "N" swapping indices, generate a lexicographically largest string. Swapping indices can be reused any number times.
Eg:
String = "abdc"
Indices:
(1,4)
(3,4)
Answer:
cdba, cbad, dbac,dbca
You should print only "dbca" which is lexicographically largest.
This might sound naive, but I completely fail to follow the question. Can someone please help me understand what the question means?
I think it's saying that, given the string mystring = "abdc", you are instructed to switch characters at the specified index pairs such that you produce the lexicographically "largest" string (i.e. such that if you lex-sorted all possible strings, it would end up at the last index). So you have two valid operations: (1) switch mystring[1] with mystring[4] ("abdc" --> "cbda"), and (2) switch mystring[3] with mystring[4] ("abdc" --> "abcd"). Also, you can multiply chain operations: either operation (1) followed by (2) ("abdc" --> "cbda" --> "cbad"), or vice versa ("abdc" --> "abcd" --> "dbca"), and so on and so forth ("abdc" --> "cbda" --> "cbad" --> "dbac").
Then you (reverse) lex-sort these and pop off the top index:
>>> allPermutations = ['abcd', 'cbad', 'abdc', 'cbda', 'dbca', 'dbac']
>>> lexSorted = sorted(allPermutations, reverse=True) # ['dbca', 'dbac', 'cbda', 'cbad', 'abdc', 'abcd']
>>> lexSorted.pop(0)
'dbca'
Based on the clarification by #ncemami I came up with this solution.
public static String swap(String str, Pair<Integer, Integer> p1, Pair<Integer, Integer> p2){
TreeSet<String> set = new TreeSet<>();
String s1 = swap(str, p1.getKey(), p1.getValue());
set.add(s1);
String s2 = swap(s1, p2.getKey(), p2.getValue());
set.add(s2);
String s3 = swap(str, p2.getKey(), p2.getValue());
set.add(s3);
String s4 = swap(s3, p1.getKey(), p1.getValue());
set.add(s4);
return set.last();
}
private static String swap(String str, int a, int b){
StringBuilder sb = new StringBuilder(str);
char temp1 = str.charAt(a);
char temp2 = str.charAt(b);
sb.setCharAt(a, temp2);
sb.setCharAt(b, temp1);
return sb.toString();
}
Here my Java solution:
String swapLexOrder(String str, int[][] pairs) {
Map<Integer, Set<Integer>> neighbours = new HashMap<>();
for (int[] pair : pairs) {
// It contains all the positions that are reachable from the index present in the pairs
Set<Integer> reachablePositionsL = neighbours.get(pair[0]);
Set<Integer> temp = neighbours.get(pair[1]); // We use it just to merge the two sets if present
if (reachablePositionsL == null) {
reachablePositionsL = (temp == null ? new TreeSet<>() : temp);
} else if (temp != null) {
// Changing the reference so every addition to "reachablePositionsL" will reflect on both positions
for (Integer index: temp) {
neighbours.put(index, reachablePositionsL);
}
reachablePositionsL.addAll(temp);
}
reachablePositionsL.add(pair[0]);
reachablePositionsL.add(pair[1]);
neighbours.put(pair[0], reachablePositionsL);
neighbours.put(pair[1], reachablePositionsL);
}
StringBuilder result = new StringBuilder(str);
for (Set<Integer> set : neighbours.values()) {
Iterator<Character> orderedCharacters = set.stream()
.map(i -> str.charAt(i - 1))
.sorted(Comparator.reverseOrder())
.iterator();
set.forEach(i -> result.setCharAt(i - 1, orderedCharacters.next()));
}
return result.toString();
}
Here an article that explain my the problem.
String = "abcd"
co_ord = [(1,4),(3,4)]
def find_combinations(co_ord, String):
l1 = []
for tup_le in co_ord:
l1.extend(tup_le)
l1 = [x-1 for x in l1]
l1 = list(set(l1))
l2 = set(range(len(String)))-set(l1)
return l1,int(''.join(str(i) for i in l2))
def perm1(lst):
if len(lst) == 0:
return []
elif len(lst) == 1:
return [lst]
else:
l = []
for i in range(len(lst)):
x = lst[i]
xs = lst[:i] + lst[i+1:]
for p in perm1(xs):
l.append([x]+p)
return l
lx, ly = find_combinations(co_ord, String)
final = perm1(lx)
print(final)
temp = []
final_list=[]
for i in final:
for j in i:
temp.append(String[j])
final_list.append(''.join(temp))
temp=[]
final_list = [ i[:ly] + String[ly] + i[ly:] for i in final_list]
print(sorted(final_list,reverse=True)[0])

How I can find the contents of inner nesting?

Lets say I have a string like this :
string = [+++[>>[--]]]abced
Now I want a someway to return a list that has: [[--],[>>],[+++]]. That is the contents of the deepest [ nesting followed by other nesting. I came up with this solution like this :
def string = "[+++[>>[--]]]"
loop = []
temp = []
string.each {
bool = false
if(it == "["){
temp = []
bool = true
}
else if( it != "]")
temp << it
if(bool)
loop << temp
}
println loop.reverse()
But this indeed takes the abced string after the last ] and put into the result!. But what I want is only [[--],[>>],[+++]]
Are there any groovy way of solving this?
You can use this, if you wouldn't mind using recursion
def sub(s , list){
if(!s.contains('[') && !s.contains('['))
return list
def clipped = s.substring(s.lastIndexOf('[')+1, s.indexOf(']'))
list.add(clipped)
s = s - "[$clipped]"
sub(s , list)
}
Calling
sub('''[+++[>>[--]]]abced''' , [])
returns a list of all subportions enclosed between braces.
['--', '>>', '+++']
If your brackets are symmetrical, you could just introduce a counter variable that holds the depth of the bracket nesting. Only depth levels above 0 are allowed in the output:
def string = "[+++[>>[--]]]abc"
loop = []
temp = []
depth = 0;
string.each {
bool = false
if(it == "["){
temp = []
bool = true
depth++;
}
else if (it == "]"){
depth--;
}
else if (depth > 0){
temp << it
}
if(bool){
loop << temp
}
}
println loop.reverse()
class Main {
private static final def pattern = ~/([^\[]*)\[(.+?)\][^\]]*/
static void main(String[] args) {
def string = "[+++[>>[--]]]abced"
def result = match(string)
println result
}
static def match(String val) {
def matcher = pattern.matcher(val);
if (matcher.matches()) {
return matcher.group(1) ? match(matcher.group(2)) + matcher.group(1) : match(matcher.group(2))
}
[val]
}
}
System.out
[--, >>, +++]
The capturing of the first group in the regex pattern could probably be improved. Right now the first group is any character that is not [ and if there are nothing in front of the first [ then the first group will contain an empty string.

Create comma separated string from 2 lists the groovy way

What I have so far is:
def imageColumns = ["products_image", "procuts_subimage1", "products_subimage2", "prodcuts_subimage3", "products_subimage4"]
def imageValues = ["1.jpg","2.jpg","3.jpg"]
def imageColumnsValues = []
// only care for columns with values
imageValues.eachWithIndex { image,i ->
imageColumnsValues << "${imageColumns[i]} = '${image}'"
}
println imageColumnValuePair.join(", ")
It works but I think it could be better. Wish there was a collectWithIndex ... Any suggestions?
There's no collectWithIndex, but you can achieve the same result with a little effort:
def imageColumns = ["products_image", "procuts_subimage1", "products_subimage2", "prodcuts_subimage3", "products_subimage4"]
def imageValues = ["1.jpg","2.jpg","3.jpg"]
def imageColumnsValues = [imageValues, 0..<imageValues.size()].transpose().collect { image, i ->
"${imageColumns[i]} = '${image}'"
}
println imageColumnsValues.join(", ")
This takes the list of items and a range of numbers from 0 size(list) - 1, and zips them together with transpose. Then you can just collect over that result.

Resources