Removing one Duplicate value from a String in Java 8 using lambdas - java

I have to remove a duplicate value from a String.
But first I have to filter the given value that needs to be deleted. And if it's a duplicate, return a new String with first duplicated value removed. And I want to do this using lambdas.
Example.
Input (filter the value: "A")
String input = "A, A, C";
Expected output
"A, C"
But if I have this.
Input (filter a value different to "A")
String input = "A, A, C";
Expected output
"A, A, C"
I.e. if the given filter-value is a duplicate, like "A", which is encountered in the string multiple times, then its first occurrence has to be removed. Otherwise, the same string should be returned.
The white spaces and commas has to be considered in the output too.
I have been tried this code:
public class Main {
public static void main(String[] args) {
String mercado = "A, B, A";
mercado = mercado.replaceAll("\\b(A)\\b(?=.*\\b\\1\\b)", "");
System.out.println( mercado );
}
}
But the output is: , B, A
And I have to remove that white space and that comma in front.

If I understood your goal correctly, you need a method that expects two string arguments.
And depending on the number of occurrences of the second string in the first string the method will return either the first string intact (if the target value is unique or not present in the first string), or will generate a new string by removing the first occurrence of the target value (the second string).
This problem can be addressed in the following steps:
Create a list by splitting the given string.
Count the number of occurrences of the target value.
If the count is <= 1 (i.e. value is unique, or not present at all) return the same string.
Otherwise remove the target value from the list.
Combine list elements into a string.
It might be implemented like this:
public static String removeFirstIfDuplicate(String source, String target) {
List<String> sourceList = new ArrayList<>(Arrays.asList(source.split("[\\p{Punct}\\p{Space}]+")));
long targetCount = sourceList.stream()
.filter(str -> str.equals(target))
.count();
if (targetCount <= 1) {
return source;
}
sourceList.remove(target);
return sourceList.stream().collect(Collectors.joining(", "));
}
main()
public static void main(String[] args) {
System.out.println(removeFirstIfDuplicate("A, A, C", "A"));
System.out.println(removeFirstIfDuplicate("A, A, C", "C"));
}
Output
A, C
A, A, C

Related

How to compare and operate two adjacent elements in one list using stream in Java?

The background is I have two String type variables str1 and str2 as inputs. At last I have to return a list that contains the consecutive prefix of str1 that smaller than the related prefix in str2.
I have the Java code like this:
public List<Character> getPrefix(String str1, String str2) {
int index = 0;
List<Character> res = new ArrayList<>();
//str1 = "1243"
//str2 = "2324"
// The answer will be "12".
while (index < str1.length() && index < str2.length() && str1.charAt(index) <= str2.charAt(index)) {
res.add(str1.charAt(index));
index++;
}
return res;
}
//the return type could either be List<String> or List<Character>
I was asked to convert this code in stream without using while or for loop, just in stream method. I plan to convert this code like this
List<String> list = new ArrayList<>();
list.add(str1);
list.add(str2);
List<String> res = list.stream()
.filter()
.reduce();
I found filter() method could select the element that match the given predicate, and reduce() method could use identity and accumulator to get one final result.
But I find I could neither have a way to operate two adjacent elements in one list, or get one pointer to compare and traverse each character in each element in the list(the element is String type).
So is there any ways that I could operate two adjacent elements in one list, so that I can compare their characters which in the same position.
You can:
Generate a stream of indexes
Get characters of both strings using the index
Select chars while valid
// The magic
public static List<Character> getPrefix(String str1, String str2) {
return IntStream
.range(0, Math.min(str1.length(), str2.length()))
.mapToObj(i -> new char[] { str1.charAt(i), str2.charAt(i) })
.takeWhile(a -> a[0] < a[1])
.map(a -> a[0])
.collect(Collectors.toList());
}
Look at the code and maybe that is what you want.
Still it could be enhanced more and do not solve the case when first string start with a value greater than second. This can be implemented also but need additional work.
(could not do in one piece because the supplier consume one element for check needed to chain dropWhile and takeWhile).
Simply, with a supplier you can do comparison between elements from the stream with elements from other data-structure.
import java.util.LinkedList;
import java.util.function.Supplier;
import java.util.stream.Collectors;
public class Pre1 {
public static void main(String[] args) {
System.out.println(new Pre1().getPre("1234", "2315"));
System.out.println(new Pre1().getPre("941234", "712315"));
System.out.println(new Pre1().getPre("2345", "341"));
}
public String getPre(String s1, String s2) {
//second list is used as supplier
LinkedList<Integer> l2 = s2.chars().boxed()
.map(t->Character.getNumericValue(t))
.collect(Collectors.toCollection(LinkedList<Integer>::new));
//l2.forEach(System.out::println);
Supplier<Integer> supplier = () -> {
// System.out.println(l2.peek());
return l2.isEmpty() ? 0 : l2.pollFirst();
};
return s1.chars().boxed()
.map(t->Character.getNumericValue(t))
.takeWhile(t->t<supplier.get())
.map(t->String.valueOf(t))
.collect(Collectors.joining());
}
}
Output
12
nothing
23

Check if String contains part of other string Java

I have some strings defined in my Java application, like so:
m3 = "T, V, E";
m2 = "T, W, E";
as an example.
Now I need to check, which parts of the strings match. So in this case, I would want a string m4, containing T, E, as a result.
In that case for example:
m1 = "A, S";
m3 = "T, V, E";
i would want an empty (but declared) string.
Or is there a better way, to do it with another method then with strings? I'm actually declaring those strings by hand. Would an array be better? If yes, how could I do it with arrays?
In Java 8 you can proceed as below :
String s1 = "T,V,E";
String s2 = "T,W,E";
List<String> l1 = Arrays.asList(s1.split(","));
List<String> l2 = Arrays.asList(s2.split(","));
List<String> result = l1.stream().filter(l2::contains).collect(Collectors.toList());
System.out.println(String.join(",", result));
The result is "T,E" as expected.
You can achieve this in many ways. One of the ways is using Set.
First, split m1 the characters by (comma) and add it to HashSet. Then split the m2 characters and add it to ArrayList. Now by the for loop try to add the ArrayList characters to HashSet. You will get false from the add method (Set.add()) if it is not added (because the character is already there). If you get false print the character or add it to another ArrayList.
String m3 = "T, V, E";
String m2 = "T, W, E";
Set<String> set = new HashSet<>(Arrays.asList(m3.split(",")));
List<String> list = Arrays.asList(m2.split(","));
for (String s : list) {
if (!set.add(s)) {
System.out.println(s);
}
}
Result will be T and E
The appropriate data structure is Set.
Set<String> m3 = new TreeSet<>();
Collections.addAll(m3, "T", "V", "E");
Collections.addAll(m3, "T, V, E".split(",\\s*")); // Alternatively.
Set<String> m2 = new HashSet<>();
Collections.addAll(m2, "T", "W", "E");
Set<String> m5 = new TreeSet<>(m2);
m5.retainAll(m3);
Java 9:
Set<String> m3 = Set.of("T", "V", "E");
Set<String> m2 = Set.of("T", "W", "E");
you can use the split() function as the following
String a="A, B, C, D";
String b="B, C, D";
String[] a_chars =a.split(", "); //returns array with A B C D
String[] b_chars =b.split(", "); //returns array with B C D
this whay you have 2 arrays of strings now you can compare them using 2 (for) loops
String result="";
for(int c=0;c<a_chars.length;c++)
{
for(int d=0;d<b_chars.length;d++)
{
if(a_chars[c].equals(b_chars[d]))
{
result+=a_chars[c]+", ";
}
}
}
now you have the result string like this result="B, C, D, "
check of the length of result is greater than zero
if so erase the lase 2 characters which are ,
if(result.length()>0)result=result.substring(0,result.length()-2);
if the length of the result string is zero that means there is no matching letters so no need to modify it
If all your String follows this pattern : ..., ..., .... , you could split them and filter only each String that is contained in the two arrays.
You can then collect them into a List and join them with , :
List<String> commonStrings = Arrays.stream(m2.split(",\\s"))
.flatMap(s-> Arrays.stream(m3.split(",\\s"))
.filter(s2.equals(s)))
.collect(Collectors.toList());
String joinedString = String.join(",", commonStrings);
Note that this code doesn't return the exact number of equals occurrences in the two Strings.
So if one String contains two A and the other one A, you will get two A in the result.
If it doesn' matter and you want to get only distinct String, you can invoke distinct() before collect().
Otherwise, to return the exact number of equals occurrences, during the processing, as soon as a String part is consumed (A for example) as the two parts are equal in the two Strings, you could create new Strings from the actual Strings but by removing this String part .
String s1 = "T,V,E";
String s2 = "T,W,E";
List<String> l1 = Arrays.asList(s1.split(","));
List<String> l2 = Arrays.asList(s2.split(","));
List<String> result = l1.stream().filter(l2::contains).collect(Collectors.toList());
System.out.println(String.join(",", result));
result = T&E
This is good answer I will tell you too this

How to list all words matching criteria from String sentence in Java

Imagine having following 'sentence' as String object:
String sentence = "AsomethingB 123 AsomethingElseB AsomethingBC abc A0B 987 ...";
How can I list everything to a String[] of words which begins with String A and ends with String B, like:
String[] words = new String[] {"AsomethingB", "AsomethingElseB", "A0B"};
// note the AsomethingBC is not here.
More globally I am looking for method which will do following:
public String[] listWords(String sentence, String startSequence, String endSequence) {
// sentence will represent String from which "extract" words
// startSequence will represent "A" from example, may contain more characters
// endSequence will represent "B" from example, may contain more characters
// return type String[] will return all matches (AsomethingB...) from example
}
Is something like this possible ?
Here's one solution:
return Pattern.compile(" ")
.splitAsStream(sentence)
.filter(w -> w.startsWith(startSequence))
.filter(w -> w.endsWith(endSequence))
.toArray(String[]::new);
You can use java 8's streams to get the result, e.g.:
public static String[] listWords(String sentence, String startSequence, String endSequence) {
return Arrays.stream(sentence.split("\\s+"))
.filter(s -> s.startsWith(startSequence))
.filter(s -> s.endsWith(endSequence))
.collect(Collectors.toList()).toArray(new String[0]);
}
This method splits the spring based on space and performs the comparison. You can call this method like this:
public static void main(String[] args) {
System.out.println(Arrays.asList(listWords("AsomethingB 123 AsomethingElseB AsomethingBC abc A0B 987", "A", "B")));
}
You can also use toLowerCase() method if you want case insensitive matching.
Update
If you words are not split by whitespace and you want to split on capital letters then you can use the following (assuming the string will contain numbers as well):
System.out.println(Arrays.asList("AsomethingB123AsomethingElseBAsomethingBCabcA0B987".split("(?=[A-Z])(?<=[A-Z])|(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)")));
This would show the tokens that are applied to the stream.
Also, on a second thought, it'll be better to add one more parameter (regex) to listWords method so that it's not tied to any specific pattern, e.g.:
public static String[] listWords(String sentence, String regex, String startSequence, String endSequence) {
return Arrays.stream(sentence.split(regex))
.filter(s -> s.startsWith(startSequence))
.filter(s -> s.endsWith(endSequence))
.collect(Collectors.toList()).toArray(new String[0]);
}
It can be called like this:
System.out.println(Arrays.asList(listWords("AsomethingB123AsomethingElseBAsomethingBCabcA0B987", "(?=[A-Z])(?<=[A-Z])|(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)", "A", "B")));
You could leverage the Java's .split command. So it could like like:
String sentence = "My Sentence AbbC";
String[] splitted = sentence.split(" ");
and then from there you can loop over the splitted array to find if your index has the desired result. Furthermore, you can also try .split("A*B") which would result in splitted containing strings that start and end with A and B respectively as being in their own singular index, while everything else would be as one long string in an index.
ex:
S: AbbD
S: Hello World, Acc
Here's a non-streams approach:
public static List<String> listWords(String sentence, String startSequence, String endSequence) {
List<String> lst = new ArrayList<>();
for (String s : sentence.split(" "))
if (s.startsWith(startSequence) && s.endsWith(endSequence))
lst.add(s);
return lst;
}
Done it as a List<String> because they're less faff than arrays. You can always convert it afterwards if you really need an array.

Replace Special characters with Character references in string using java

I have a String with special characters which I want to be replaced by corresponding reference.
For example
InputString -> Hi <Nishanth> How &are you !
OutputString -> Hi &ltNishanth&gt How &ampare you &excl
I tried using concept of replace. But I couldn't achieve the desired result ..
I want a function which would do it for me in Java.
replaceAll should be able to do the job just fine.
First, let's make a quick tuple class to represent a pair of Strings: the string to search for and the string to replace that with:
private static class StringTuple{
private String k;
private String v;
public StringTuple(String one, String two){
k = one;
v = two;
}
}
With that, we can build a list of special characters to search for and their corresponding replacements. Note that this list is going to be used in the order that we create it, so it's important that we replace special characters that might show up in other replacements first (such as & or ;).
ArrayList<StringTuple> specialChars = new ArrayList<>();
specialChars.add(new StringTuple("&", "&"));
specialChars.add(new StringTuple("<", "<"));
specialChars.add(new StringTuple(">", ">"));
Finally, we can write a function that loops over the list of special chars and replaces all occurrences with the replacement string:
public static String replaceSpecialChars(String s, ArrayList<StringTuple> specialChars){
for(StringTuple e: specialChars){
s = s.replaceAll(e.k, e.v);
}
return s;
}
Here's a runnable main based off of the above code:
public static void main(String[] args) {
ArrayList<StringTuple> specialChars = new ArrayList<>();
specialChars.add(new StringTuple("&", "&"));
specialChars.add(new StringTuple("<", "<"));
specialChars.add(new StringTuple(">", ">"));
System.out.println(replaceSpecialChars("Hi <Nishanth> How are &you !", specialChars));
}
Output: Hi <Nishanth> How are &you !

Conjunctive regex matching tokens in Java

I have a large List<String> where each String is a sentence containing 1+ "tokens" (prefixed by "a" or "b" and followed by a positive integer):
List<String> tokenList = new ArrayList<String>()
tokenList.add("How now a1 cow.")
tokenList.add("The b1 has oddly-shaped a2.")
tokenList.add("I like a2! b2, b2, b2!")
// etc.
I want to write a function that accepts a vararg list of tokens and will return a subset of the tokenList of String that contain all the token arguments. For instance:
public class TokenMatcher {
List<String> tokenList; // Same tokenList as above
List<String> findSentencesWith(String... tokens) {
List<String> results = new ArrayList<String>();
StringBuilder sb = new StringBuilder();
// Build up the regex... (TODO: this is where I'm going wrong)
for(String t : tokens) {
sb.append(t);
sb.append("|");
}
String regex = sb.toString();
for(String sentence : tokenList) {
if(sentence.matches(regex)) {
results.add(sentence);
}
}
return results;
}
}
Again, the regex has to be constructed in such a way that all the tokens passed into the function have to exist inside the sentence in order for the match to be true. Hence:
TokenMatcher matcher = new TokenMatcher(tokenList);
List<String> results = matcher.findSentencesWith("a1"); // Returns 1 String ("How now a1 cow")
List<String> results2 = matcher.findSentencesWith("b1"); // Returns 1 String ("The b1 has oddly-shaped a2.")
List<String> results3 = matcher.findSentencesWith("a2"); // Returns the 2 Strings with a2 in them since "a2" is all we care about...
List<String> results4 = matcher.findSentencesWith("a2", "b2"); // Returns 1 String ("I like a2! b2, b2, b2!.") because we care about BOTH tokens
The last example (results4) is important because although the "a2" token appears in several sentences, with results4 we are asking the method to give us matches for sentences containing both tokens. This is n-ary conjunctive, meaning that if we specified 50 tokens as parameters, we would only want sentences with all 50 tokens.
The above findSentencesWith example is my best attempt so far. Any ideas?
Given your stated requirements that neither order nor frequency matter, I don't see the need to use regexes at all in this case.
Rather, you can compare every string with all the example tokens that were provided and see if all are contained in the string. If so, it's in the result set. The first time a missing token is detected, that string is removed from the result set.
This sort of code would look something like this:
TokenMatcher.java
package so_token;
import java.util.*;
public class TokenMatcher {
public TokenMatcher(List<String> tokenList) {
this.tokenList = tokenList;
}
List<String> tokenList;
List<String> findSentencesWith(String... tokens) {
List<String> results = new ArrayList<String>();
// start by assuming they're all good...
results.addAll(tokenList);
for (String str : tokenList) {
for(String t : tokens) {
// ... and remove it from the result set if we fail to find a token
if (!str.contains(t)) {
results.remove(str);
// no point in continuing for this token
break;
}
}
}
return results;
}
public static void main (String[] args) throws java.lang.Exception
{
List<String> tokenList = new ArrayList<String>();
tokenList.add("How now a1 cow.");
tokenList.add("The b1 has oddly-shaped a2.");
tokenList.add("I like a2! b2, b2, b2!");
TokenMatcher matcher = new TokenMatcher(tokenList);
List<String> results = matcher.findSentencesWith("a1"); // Returns 1 String ("How now a1 cow")
for (String r : results) {
System.out.println("1 - result: " + r);
}
List<String> results2 = matcher.findSentencesWith("b1"); // Returns 1 String ("The b1 has oddly-shaped a2.")
for (String r : results2) {
System.out.println("2 - result: " + r);
}
List<String> results3 = matcher.findSentencesWith("a2"); // Returns the 2 Strings with a2 in them since "a2" is all we care about...
for (String r : results3) {
System.out.println("3 - result: " + r);
}
List<String> results4 = matcher.findSentencesWith("a2", "b2"); // Returns 1 String ("I like a2! b2, b2, b2!.") because we care about BOTH tokens
for (String r : results4) {
System.out.println("4 - result: " + r);
}
}
}
This results in the following output:
1 - result: How now a1 cow.
2 - result: The b1 has oddly-shaped a2.
3 - result: The b1 has oddly-shaped a2.
3 - result: I like a2! b2, b2, b2!
4 - result: I like a2! b2, b2, b2!
Slightly tweaked, runnable code (mainly around no package name and non-public class, so it'll run on the site) on ideone.
Note: Based on the information you provided, and since the function is accepting a list of tokens, it appears that contains would be sufficient for determining whether or not the token is present. However, if it turns out there are additional constraints on that, such as the token must be followed by a space or one out of a set of punctuation, or something like that, in order to count as a token, then I would recommend using regexes -- on an individual-token basis -- replacing contains with matches and passing in the regex defining what you want surrounding the token.
It may also be desirable to have a function that validates your tokenList that is passed to the findSentencesWith function.

Categories