how to merge 2 lists by regex matching in java - java

I have 2 lists,
listA = Amy, Bob, Dan
and
listB = Amy123, Bob23, Pam92, Dan45, Vince55
How do I create a list that contains the values in listB that begin with the values in listA, using regex?
The result list should look like this:
mergedList = Amy123, Bob23, Dan45

In case the matching criterion is that the elements should start with the same string:
List<String> listA = Arrays.asList("Amy", "Bob", "Dan");
List<String> listB = Arrays.asList("Amy123", "Bob23", "Pam92", "Dan45", "Vince55");
List<String> mergedList = listB.stream().filter(elementB -> listA.stream().anyMatch(elementA -> elementB.startsWith(elementA))).collect(Collectors.toList());

My Observation :
1) You have two lists : listA and listB
2) logic is to match items of listA with listB. If listA item is found(in part using regex or some other method OR as whole) in listB, then push listB item to mergelist, otherwise ignore listB item.
Heres what you can do :
1) I am using Java8 lambdas.
2) I havent used regex in this code. I guess you dont really need regex here. After all you basically are searching a string in another string as part or in whole. I have used contains() method.
public static void main(String[] args){
List<String> list1 = Arrays.asList("Amy","Bob","Dan");
List<String> list2 = Arrays.asList("Amy123","Bob23","Pam92","Dan45","Vince55");
List<String> mergedList = new ArrayList<>();
list1.forEach(item1 -> {
list2.forEach(item2 -> {
if(item2.contains(item1))
mergedList.add(item2);
});
});
mergedList.forEach(System.out::println);
}
3) The code outputs this :
Amy123
Bob23
Dan45

Related

Efficient way to remove items in a list that contain certain words?

Very simple question, I have
List<String> forbidden_words = Arrays.asList("test","one","two");
List<String> list1 = Arrays.asList("eiofjfrgj_test","oiione","rrrtwo", "normal", "word");
I want to remove the elements in list1 that contain forbidden words so I get "normal" & "word" in list1. What's the best way to do this?
Here's how I would write that:
List<String> forbiddenWords = Arrays.asList("test","one","two");
List<String> words = Arrays.asList("eiofjfrgj_test","oiione","rrrtwo", "normal", "word");
List<String> filtered = words.stream()
.filter(word -> !forbiddenWords.stream().anyMatch(forbiddenWord -> word.contains(forbiddenWord)))
.collect(Collectors.toList());
System.out.println(filtered);
Use regex and removeIf():
// Input from question
List<String> forbidden_words = Arrays.asList("test","one","two");
List<String> list1 = Arrays.asList("eiofjfrgj_test","oiione","rrrtwo", "normal", "word");
// Make list1 mutable
list1 = new ArrayList<>(list1);
// Remove forbidden words using regex, so it works case-insensitively
Pattern p = Pattern.compile(forbidden_words.stream().map(Pattern::quote).collect(Collectors.joining("|")),
Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
list1.removeIf(s -> p.matcher(s).find());
// See result
System.out.println(list1);
Output
[normal, word]
String array is immutable (or to be precise: fixed). The only way to do that is to convert the string array to a List (using Arrays.asList()), remove the "forbidden" word and finally convert the list back to String array (using the method toArray())
To begin with, most other answer answers are not efficient but are short.
Below is another possible way you would do it.
public static String[] naiveFiltering(String[] forbidden_words, String[] list1 ){
List<String> filteredList = new ArrayList<>(); //extra memory
for(String str: list1){
boolean containsForbidden = false;
for(String forbidden: forbidden_words){
if(str.contains(forbidden)){ // o(mn)
containsForbidden = true;
break;
}
}
if(!containsForbidden)
filteredList.add(str);
}
String[] filteredArray = new String[filteredList.size()];
for(int i=0;i<filteredArray.length;i++){
filteredArray[i] = filteredList.get(i); //extra copying
}
return filteredArray;
}
I am assuming that "efficient" means something more than just a naive approach like most other answers including mine.
You can do two things to make it efficient:
Change your representation to a LinkedList instead of an array so that you can remove from an index without having to copy over to a new list/array.
Use KMP for String matching which is O(N) instead of String.contains() which is a naive implementation with O(MN) worst-case complexity.

Find items if not equal between lists

I Have 2 ArrayList in my project. I want to get items which is not equal.
For Example:
LIST 1 - LIST 2
AB ------- AB
BA ------- BA
CC
I wanna get this CC. I'm doing like this:
ArrayList<String> alllist= new ArrayList<>(ArrayList<String> 1);
for (String i : ArrayList<String> 1) {
for (String j : ArrayList<String> 2) {
if (i.equals(j)) {
alllist.remove(i);
break;
}
}
}
This work if I haved 3 or 4 items in ArrayList but when I add 200 items this method doesn't work fine and getting wrong list.
Any idea? what can I do more?
Thanks a lot.
If I understand your question correctly, you are looking for a symmetric difference. You can use CollectionUtils.disjunction from Apache Commons Collections
Given:
List<String> list1 = Arrays.asList("AB", "BA", "DD");
List<String> list2 = Arrays.asList("AB", "BA", "CC");
Action:
System.out.println(CollectionUtils.disjunction(list1, list2));
Result:
[DD, CC]
If you need everything in list 1 but not list 2
1) Walk the first list and add each element to a HashSet.
2) use set.removeAll(list2) to remove everything in list 2.
The remainder is what's in list1 and not list2.
If you need to get everything in either list not in the other, you can repeat that in reverse. This should reverse the operation to O(n+m) where n is the length of list 1 and m is the length of list 2. Your pseudocode is O(n*m).
HashSet firstButNotSecond = new HashSet(list1);
firstButNotSecond.removeAll(list2);
HashSet secondButNotFirst = new HashSet(list2);
secondButNotFirst.removeAll(list1);
ArrayList<String> list2 = new ArrayList();
list2.add("AB");
list2.add("BA");
ArrayList<String> list1 = new ArrayList();
list1.add("AB");
list1.add("BA");
list1.add("C");
//remove all the element from the list1 which are also in list2
list1.removeAll(list2);
System.out.println("Result: " + list1); //only C will left behind

Separating the elements of arraylist

I have an ArrayList that contains a messageId, then a -, then a username.
Example : E123-sam
I want to divide each element of my List such that the part before the - goes to one ArrayList and the part after that goes to an other ArrayList.
How can I do it?
Assuming you have these ArrayLists:
List<String> allStrings;
// ... initialization and filling of 'allStrings'
List<String> messageIDs = new ArrayList<>();
List<String> userNames = new ArrayList<>();
you can loop through elements of the ArrayList and use String#split(delimiter) to separate the string based in the delimiter:
for (String s : allStrings) {
String[] parts = s.split("-");
messageIDs.add(parts[0]);
userNames.add(parts[1]);
}
Note: This will work if all the strings in allStrings follows the pattern "something-something". If not, then you can check if the length of parts is correct before accessing its elements, otherwise you will get a IndexOutOfBoundsException.
If you plan to use Java 8, you could do:
List<String> listOfIds = original.stream().map(e -> e.split("-")[0]).collect(Collectors.toList());
List<String> listOfUsernames = original.stream().map(e -> e.split("-")[1]).collect(Collectors.toList());

Merge two list into a single list

I have a ArrayList as below.
ArrayList<ArrayList<String>> a = new ArrayList<ArrayList<String>>();
Where ArrayList 'a' contains two ArrayList of string as below.
[a,b,c,d] & [1,2,3,4]
How to merge these two list into a single list as below.
[a,b,c,d,1,2,3,4]
Thanks In Advance.
You combine a foreach loop and the addAll method.
Example
ArrayList<String> combined = new ArrayList<String>();
for(ArrayList<String> list : a) {
combined.addAll(list);
}
How this works?
A for each loop will traverse through every member of a Collection. It has a temporary variable, in this case list that it assigns the current element too. All you're doing is adding every element inside each value for list, to one ArrayList named combined.
Just iterate through all the inner lists of a using foreach loop and addAll to result arraylist
ArrayList<String> merged = new ArrayList<String>();
for(ArrayList<String> list : a){
merged.addAll(list);
}
EDIT:
As #Lubo pointed out.
Note that this way you can end up with many arrays being created and thrown away internally in ArrayList. If you have large lists (number of contained elements), consider looking here: Union List
This should work
ArrayList<ArrayList<String>> a = new ArrayList<ArrayList<String>>();
List<String> result = new ArrayList<String>();
for (ArrayList<String> arrayList : a) {
result.addAll(arrayList);
}
Look into main loop and get each list in it and add to your result list.
We have some other ways too, If you can use Apache commons-collection
ListUtils.union(java.util.List list1, java.util.List list2)
Returns a new list containing the second list appended to the first list.
Use ArrayList.addAll(). Something like this should work (assuming lists contain String objects; you should change accordingly).
List<String> combined = new ArrayList<String>();
combined.addAll(firstArrayList);
If you need an Iterable, you can use Guava:
Iterables.concat(Iterable<? extends Iterable<? extends T>> inputs)
And if you really need a List, you can cast a resulting Iterable to a List using this:
Lists.newArrayList(Iterable<? extends E> elements)
or
Lists.newLinkedList(Iterable<? extends E> elements)
Java 8 streams provide another solution:
List<List<String>> list = Arrays.asList(
Arrays.asList("1", "2"),
Arrays.asList("3", "4"),
Arrays.asList("5", "6")
);
List<String> merged = list
.stream()
.reduce(new ArrayList<>(),(accumulator, sublist) -> {accumulator.addAll(sublist);return accumulator;});
System.out.println(merged);
It is similar to the accepted answer: you loop through your list (using Stream.reduce) to add all of your sublists elements to your merged list.
List<Integer> one = Arrays.asList(1, 2,3);
List<Integer> two = Arrays.asList(4, 5,6);
List<Integer> out = Stream.of(one, two)
.collect(ArrayList::new, (listStream, item) -> listStream.addAll(item), (item1, item2) -> {});
System.out.println(out);
Merging lists without loop with Guava
Using FluentIterable.transformAndConcat.
Applies function to each element of this fluent iterable and returns a fluent iterable with the concatenated combination of results. function returns an Iterable of results.
Usage
List<String> combined = FluentIterable.from(a)
.transformAndConcat(Functions.identity())
.toList();

Merge 3 arraylist to one

I want to merge down 3 arraylist in one in java. Does anyone know which is the best way to do such a thing?
Use ArrayList.addAll(). Something like this should work (assuming lists contain String objects; you should change accordingly).
List<String> combined = new ArrayList<String>();
combined.addAll(firstArrayList);
combined.addAll(secondArrayList);
combined.addAll(thirdArrayList);
Update
I can see by your comments that you may actually be trying to create a 2D list. If so, code such as the following should work:
List<List<String>> combined2d = new ArrayList<List<String>>();
combined2d.add(firstArrayList);
combined2d.add(secondArrayList);
combined2d.add(thirdArrayList);
What about using java.util.Arrays.asList to simplify merging?
List<String> one = Arrays.asList("one","two","three");
List<String> two = Arrays.asList("four","five","six");
List<String> three = Arrays.asList("seven","eight","nine");
List<List<String>> merged = Arrays.asList(one, two, three);
Using Java 8 Streams:
List of List
List<List<String>> listOfList = Stream.of(list1, list2, list3).collect(Collectors.toList());
List of Strings
List<String> list = Stream.of(list1, list2, list3).flatMap(Collection::stream).collect(Collectors.toList());
Using Java 9 List.of static factory method (Warning: this list is immutable and disallows null)
List<List<String>> = List.of​(list1, list2, list3);
Where list1, list2, list3 are of type List<String>

Categories