How I can find the contents of inner nesting? - groovy

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.

Related

Groovy: Get index of all occurences of sublist from arraylist

I am new to groovy and trying to find the indexes of all sublists in a list.
I am trying to use something like Collections.indexOfSubList like in java but it gives exception saying it applies on Lists and not ArrayLists.
So I am trying to define my own function. I am finding all the indices of all the elements in the smaller list existing in the longer list and then subtracting the indices of the result array. If it comes to 1 then I am considering that index to a sublist.
I know that I have the logic a little twisted. Can somebody guide with a better and efficient way of doing this.
Below is my code:
List list1 = [1,2,3,4,5,6,1,2,3]
List list2 = [1,2]
index1 = list1.findIndexValues {
it == list2[0];
}
index2 = list1.findIndexValues {
it == list2[1];
}
println index1
println index2
result = []
for (int i = 0; i < index1.size(); i++) {
result.add(index2[i]-index1[i]);
}
println result
Edit: no longer uses Collections due to new issue re: Elastic Search.
The following code traverses along the source list, creating a sublist. It checks the sublist to see if it starts with the target list. See the asserts below (e.g. the indexes are 0-based):
def listStartsWithSubList = { source, target ->
def result = false
if (source.size() >= target.size()) {
result = true
target.eachWithIndex { item, index ->
result = result && (item == source[index])
}
}
result
}
def indexOfSubLists = { source, target ->
def results = []
source.eachWithIndex { item, index ->
def tmpList = source[index..source.size()-1]
if (listStartsWithSubList(tmpList, target)) {
results << index
}
}
results
}
assert [1] == indexOfSubLists([1,2,3], [2,3])
assert [2] == indexOfSubLists([1,2,3], [3])
assert [] == indexOfSubLists([1,2,3], [4])
assert [0,6] == indexOfSubLists([1,2,3,4,5,6,1,2,3], [1,2])

Performance issue with Groovy lists / maps

I have this code which compares two lists and find differences, so far so good, it works fine for small lists. Now Im testing with huge lists.
which contains both more than 300000 maps. It takes more than 5 hours to process it. is that normal? How can I reduce the procssing time?
def list1 = [
[cuInfo:"T12",service:"3",startDate:"14-01-16 13:22",appId:"G12355"],
[cuInfo:"T13",service:"3",startDate:"12-02-16 13:00",appId:"G12356"],
[cuInfo:"T14",service:"9",startDate:"10-01-16 11:20",appId:"G12300"],
[cuInfo:"T15",service:"10",startDate:"26-02-16 10:20",appId:"G12999"]
]
​
def list2 = [
[name:"testname1",cuInfo:"T12",service:"3",startDate:"14-02-16 10:00",appId:"G12351"],
[name:"testname1",cuInfo:"T13",service:"3",startDate:"14-01-16 13:00",appId:"G12352"],
[name:"testname1",cuInfo:"T16",service:"3",startDate:"14-01-16 13:00",appId:"G12353"],
[name:"testname2",cuInfo:"T14",service:"9",startDate:"10-01-16 11:20",appId:"G12301"],
[name:"testname3",cuInfo:"T15",service:"10",startDate:"26-02-16 10:20",appId:"G12999"],
[name:"testname3",cuInfo:"T18",service:"10",startDate:"26-02-16 10:20",appId:"G12999"]
]
def m1 = [:]
def m2 = [:]
def rows = list1.collect { me ->
[me, list2.find { it.cuInfo == me.cuInfo && it.service == me.service }]
}.findAll {
it[1]
}.findAll {
/*
* This is where the differences are identified.
* The 'name' attribute is excluded from the comparison,
* by including only the desired attributes.
*/
it[0] != it[1].subMap(['cuInfo', 'service', 'startDate', 'appId'])
}.collect {
/*
* At this point the list only contains the row pairs
* which are different. This step identifies which columns
* are different using asterisks.
*/
(m1, m2) = it
m1.keySet().each { key ->
if(m1[key] != m2[key]) {
m1[key] = "*${m1[key]}*"
m2[key] = "*${m2[key]}*"
}
}
[m1, m2]
}.collect {
[it[0].values(), it[1].values()].flatten() as String[]
}
Maybe this will help a little. I didn't have time to test but your code has a lot of collects and find alls that can cause performance issues
def results = []
list1.each{ lst1 ->
def list1WithDifferences = []
def list2WithDifferences = []
def add = false
def match = list2.find{ lst2 -> lst2.cuInfo == lst1.cuInfo && lst2.service == lst1.service }
match.each{k, v ->
if(k != 'name'){
if(v != lst1[k]){
add = true
list1WithDifferences << "*${lst1[k]}*"
list2WithDifferences << "*${v}*"
}else{
list1WithDifferences << v
list2WithDifferences << v
}
}else{
list2WithDifferences << v
}
}
if(add){
results << list1WithDifferences + list2WithDifferences
}
}
println(results)

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])

Check if a string is a shuffle of two other given strings

This is a question from The Algorithm Design Manual:
Suppose you are given three strings of characters: X, Y, and Z, where |X| = n,
|Y| = m, and |Z| = n+m. Z is said to be a shuffle of X and Y if and only if Z can be formed by interleaving the characters from X and Y in a way that maintains the left-to ­right ordering of the characters from each string.
Give an efficient dynamic ­programming algorithm that determines whether Z is a shuffle of X and Y.
Hint: the values of the dynamic programming matrix you construct should be Boolean, not numeric
This is what I tried:
Initially, I made a 1-D char array and pointers to the starting characters of X,Y,Z respectively. If Z-pointer with matches X-pointer store X in the char array else check the same with Y-pointer.If each entry in the char array is not different from its last entry, Z is not interleaved.
Can someone help me with this problem?
First, let's start with some definitions. I write X[i] for the ith element of X and X[i) for the substring of X starting at index i.
For example, if X = abcde, then X[2] = c and X[2) = cde.
Similar definitions hold for Y and Z.
To solve the problem by dynamic programming, you should keep a 2D boolean array A of size (n+1) x (m+1). In this array, A[i, j] = true if and only if X[i) and Y[j) can be interleaved to form Z[i+j).
For an arbitrary (i, j), somewhere in the middle of the 2D array, the recurrence relation is very simple:
A[i, j] := X[i] = Z[i+j] and A[i+1, j]
or Y[j] = Z[i+j] and A[i, j+1]
On the edges of the 2D array you have the case that either X or Y is already at its end, which means the suffix of the other should be equal to the suffix of Z:
A[m, j] := Y[j) = Z[m+j)
A[i, n] := X[i) = Z[i+n)
A[m, n] := true
If you first fill the border of the array (A[m, j] and A[i, n], for all i, j), you can then simply loop back towards A[0, 0] and set the entries appropriately. In the end A[0, 0] is your answer.
Following approach should give you an idea.
Define the condition d(s1,s2,s3) = (s1 + s2 == s3) { s3 is a shuffle of s1 and s2 }
We have to find d( X, Y, Z ).
if lengths of s1 and s2 are 1 each and length of s3 = 2,
d( s1,s2,s3 ) = { (s1[0] == s3[0] && s2[0] == s3[1]) || (s1[0] == s3[1] && s2[0] == s3[0])
Similarly d can be obtained for empty strings.
For strings of arbitrary length, following relation holds.
d( s1,s2,s3 ) = { ( d( s1-s1[last],s2,s3 - s3[last]) && s1[last] == s3[last] )
|| ( d( s1,s2 - s2[last],s3 - s3[last]) && s2[last] == s3[last] )
}
You can compute the d() entries starting from zero length strings and keep checking.
It is defined by following recurrence relation:-
S(i,j,k) = false
if(Z(i)==Y(k))
S(i,j,k) = S(i,j,k)||S(i+1,j,k+1)
if(Z(i)==X(j))
S(i,j,k) = S(i,j,k)||S(i+1,j+1,k)
Where S(i,j,k) corresponds to Z[i to end] formed by shuffle of X[j to end] and Y[K to end]
You should try to code this into DP on your own.
I think this is quite easy if you are solving this problem by using this approach with java
Java Based Solution
public class ValidShuffle {
public static void main(String[] args) {
String s1 = "XY";
String s2 = "12";
String results = "Y21XX";
validShuffle(s1, s2, results);
}
private static void validShuffle(String s1, String s2, String result) {
String s3 = s1 + s2;
StringBuffer s = new StringBuffer(s3);
boolean flag = false;
char[] ch = result.toCharArray();
if (s.length() != result.length()) {
flag = false;
} else {
for (int i = 0; i < ch.length; i++) {
String temp = Character.toString(ch[i]);
if (s3.contains(temp)) {
s = s.deleteCharAt(s.indexOf(temp));
s3 = new String(s);
flag = true;
} else {
flag = false;
break;
}
}
}
if (flag) {
System.out.println("Yes");
} else {
System.out.println("No");
}
}
}
If any problem in my code then comment me please. thank you
function checkShuffle(str1, str2, str3) {
var merge=str1+str2;
var charArr1= merge.split("").sort();
var charArr2= str3.split("").sort();
for(i=0;i<str3.length;i++){
if(charArr1[i] == charArr2[i]){
return true;
}
}
return false;
}
checkShuffle("abc", "def", "dfabce"); //output is true
JAVASCRIPT BASED SOLUTION
const first = "bac";
const second = "def"
const third = "dabecf";
function createDict(seq,str){
let strObj = {};
str = str.split("");
str.forEach((letter,index)=>{
strObj[letter] = {
wordSeq: seq,
index : index
} ;
})
return strObj;
}
function checkShuffleValidity(thirdWord,firstWord,secondWord){
let firstWordDict = createDict('first',firstWord);
let secondWordDict = createDict('second',secondWord);
let wordDict = {...firstWordDict,...secondWordDict};
let firstCount=0,secondCount = 0;
thirdWord = thirdWord.split("");
for(let i=0; i<thirdWord.length; i++){
let letter = thirdWord[i];
if(wordDict[letter].wordSeq == "first"){
if(wordDict[letter].index === firstCount){
firstCount++;
}else{
return false
}
}else{
if(wordDict[letter].index === secondCount){
secondCount++;
}else{
return false;
}
}
}
return true;
}
console.log(checkShuffleValidity(third,first,second));
Key points:
All strings shouldn't be null or empty.
The sum of the 2 strings length should be equal to the third string.
The third string should not contain the substrings of the 2 strings.
Else create arrays of characters , sort and compare.
Code:
public static boolean validShuffle(String first, String second, String third){
boolean status=false;
if((first==null || second==null || third==null) || (first.isEmpty()|| second.isEmpty() || third.isEmpty())){
status = false;
} else if((first.length()+second.length()) !=third.length()){
//check if the sum of 2 lengths equals to the third string length
status = false;
} else if(third.indexOf(first,0)!=-1 || third.indexOf(second,0)!=-1){
//check if the third string contains substrings
status = false;
} else {
char [] c1_2=(first+second).toCharArray();
char [] c3 =third.toCharArray();
Arrays.sort(c1_2);
Arrays.sort(c3);
status=Arrays.equals(c1_2, c3);
}
return status;
}

Groovy: indexes of substrings?

How do I find the indexes of all the occurances of a substring in a large string -
(so basically ,and extension of the "indexOf" function) . Any ideas?
Current situation:
def text = " --- --- bcd -- bcd ---"
def sub = "bcd"
text.indexOf(sub)
// = 9
I want something like:
def text = " --- --- bcd -- bcd ---"
def sub = "bcd"
text.indexesOf(sub)
// = [9,15]
Is there such a function? How should I implement it otherwise? (in a non trivial way)
You could write a new addition to the String metaClass like so:
String.metaClass.indexesOf = { match ->
def ret = []
def idx = -1
while( ( idx = delegate.indexOf( match, idx + 1 ) ) > -1 ) {
ret << idx
}
ret
}
def text = " --- --- bcd -- bcd ---"
def sub = "bcd"
text.indexesOf(sub)
There is nothing I know of that exists in groovy currently that gets you this for free though
This is a relatively easy approach:
String.metaClass.indexesOf = { arg ->
def result = []
int index = delegate.indexOf(arg)
while (index != -1) {
result.add(index);
index = delegate.indexOf(arg, index+1);
}
return result;
}
Note that this will find overlapping instances (i.e. "fooo".indexesOf("oo") will return [1, 2]). If you don't want this, replace index+1 with index+arg.length().

Resources