I'm have defined a list like the below
List<String> list = List.of("val1", "val2", "val3");
Now I have the below String
String myStr = "rel1,wel12,val1";
Now I need to check if the String has anyone one of the elements of the list(in the above case its true as it has val1, next is get that value into a variable
I have tried the below and it works, but I'm sure there is a better way to do that using any of the Collections libraries
List<String> list = List.of("val1", "val2", "val3");
String myStr = "rel1,wel12,val1";
String matchedStr =StringUtils.EMPTY;
String[] vals = myStr.split(",");
for(String val:vals) {
if(list.contains(val){
matchedStr=val;
break;
}
}
You can use Java Streams to get the first String that match:
Optional<String> result = Stream.of(vals).filter(list::contains).findFirst();
Your way is alright if the lists aren't too big. I am considering the string as a list too because it can be made one from splitting it as you've done already. You can make a set from the bigger one, and iterate on the smaller one.
Another way to go would be to find the intersection of two lists.
List<String> list = Arrays.asList("red", "blue", "blue", "green", "red");
List<String> otherList = Arrays.asList("red", "green", "green", "yellow");
Now we can find the inttersection:
Set<String> result = list.stream()
.distinct()
.filter(otherList::contains)
.collect(Collectors.toSet());
The result should contain "red" and "green".
Some more info on collectors.
Depending on the possible values in the problem domain, there may be no need to split the input string. Just call String#contains.
If so, you can flip your logic. Rather than loop on the split parts, loop on the target list of strings. For each string in the list, ask if your unprocessed input string contains that element. If yes, bail out of the loop.
Tip: If this code is in a method returning a string, and returns null if no match was found, learn about returning an Optional.
I would favour Zobayer's answer, or using List#retainAll.
final List<String> first = List.of("one", "two", "three");
final List<String> out = new ArrayList<>(Arrays.asList("five,four,three".split(",")));
out.retainAll(first);
out contains the single entry, "three".
Related
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.
I have a simple LinkedList that contains strings.
LinkedList<String> list = new LinkedList<String>();
list.add("A, B, C, D");
list.add("R");
list.add("A");
list.add("C, D");
So, our LinkedList is: [ "A, B, C, D", "R", "A" ,"C, D" ]
As you can see, "A" and "C, D" are already contained in "A,B,C,D".
What is the most efficient way to remove the contained strings?
First, you can use contains() method before adding new values (as long as you're adding single String every time, but you are not...).
Second, it seems like this "problem" can be easily avoided, if you will change the way you're adding the strings, or the LinkedList restriction..
Anyway, this is a simple method that might suite your need:
private void deleteIfContains(LinkedList<String> list, String str) {
Iterator<String> headIterator = list.iterator();
HashMap<Integer, String> newValues = new HashMap<>();
int index = 0;
while (headIterator.hasNext()) {
String headString = headIterator.next();
if (headString.contains(str)) {
headIterator.remove();
//replace method won't handle ','..you will need to use regex for it
newValues.put(index, headString.replace(str, ""));
}
index++;
}
//Avoid ConcurrentModificationException
for (int i : newValues.keySet()) {
list.add(i, newValues.get(i));
}
}
I would suggest you use a Set instead but you would have to contain every letter in a single String variable (maybe you should use Character?).
If you really want to stick to your own idea consider implementing your own Set. But first figure out what happens in that situation :
LinkedList<String> list = new LinkedList<String>();
list.add("A, B, C, D");
list.add("C, E");
C should be rejected but what about E?
As #nikowis says the best solution depends on the problem definition.
If the values are the elements "A", "B", "C", "D", ... the more efficient solution (on computation time) can be to transform the list into a List> or a single Set.
If the values are "substring", for example "C, E" is ONE value (and not two "C" and "E") you can use a substring "Trie" (https://en.wikipedia.org/wiki/Trie). It can find very quickly the presence of the substring in the trie (O(log N) with N the length of the string to add).
Convert the csv-format string to string values. Then store them as set element. If method add() returns true, that means value is already present.
String[] values = csvStr1.split(",");
Set<String> hashSet = new HashSet<String>(Arrays.asList(values));
String[] values2 = csvStr2.split(",");
for (String value: values2 ) {
if( hashSet.add(value) == true ) {
//value already present. Ignore this or do whatever you want.
}
}
So lets say I want to make an array of nine country names. I have the code to create the array:
String[] countryName = new String[9];
Lets say I wanted to add nine unique country names to this array. I could do something like this:
countryName[0] = "Mexico";
countryName[1] = "United States";
and so on. But is there a way I could add all of the names at once? Maybe something like an add() statement?
you can initialize the array with:
String[] countryName = new String[]{"Mexico", "Italy", "Spain"};
You can write simple utility method using varargs
static void addAll(String[] arr, String ... elements)
{
if (elements != null)
{
System.arraycopy(elements, 0, arr, 0, elements.length);
}
}
Usage
addAll(countryName, "Mexico", "US", "Ukraine");
Use an ArrayList this has the Add method.
ArrayList<String> countryName = new ArrayList<String>();
countryName.add("Mexico");
countryName.add("United States");
countryName.add("Dominican Republic");
countryName.add("...");
Enlist all contries in String and use split
String str="Country1,Country2,Country3";
String array[]=str.split(",");//You even don't need to initialize array
Use delimeter carefully to avoid extra spaces.
NOTE:
As this is one of the ways to add values to array but still I suggest you to go for Michel Foucault's answer as split will have more overhead than direct initialization.
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());
I was wondering if it is possible to do a select * where value is in Java String[] or do I need to build a string of values from the string array first?
I am trying to find the best way of doing this technically without singular selects or building a string of values from the array.
Thanks for your time.
String[] lookupValues = new String[]{"1", "2", "3", "4"};
Select * from database where value in (lookupvalues)
try Arrays.toString(lookupvalues) or write a utility function.
public String toString(String[] values, boolean addQuotes) {
StringBuilder buff = new StringBuilder();
for(String value : values) {
if(addQuotes) {
buff.append(String.format("\"%s\"", value)).append(",");
} else {
buff.append(value).append(",");
}
}
buff.deleteCharAt(buff.length()-1); // delete the last comma
return buff.toString();
}
Are you looking to search for a string in array? If yes, you might want to look at Collections.binarySearch() or Arrays.binarySearch() - but please not that the collections or arrays need to be sorted before doing binary search
I know that this is not a direct answer to your question considering only arrays. I suggest you to use Guava since it offers a implementation of filter on Java Collections. Using proven libraries will give you flexibility if you use different kind of filters.
You can easily convert your array into proper collection
String[] lookupValues = new String[]{"1", "2", "3", "4"};
List<String> list = new ArrayList<String>(Arrays.asList(lookupValues));
And filter it with Guava filters:
Collection<String> filtered = Collections2.filter(list,
Predicates.containsPattern("3"));
print(filtered);
will find
3
If you want filtered collection as a list, you can use this something like this from Guava:
List<String> filteredList = Lists.newArrayList(Collections2.filter(
list, Predicates.containsPattern("3")));