Reputation: 107
I want to print duplicate characters from a string using collections(Set) only.
I have written code but it will show the correct result if String is "ashish" but fails if the String is "ashish java" because of occurrence of char 'a' is three times.
public class DuplicateStringMethod {
public static void duplicateString(String str) {
char[] cArray = str.toCharArray();
Set<Character> set = new HashSet<Character>();
for(char c:cArray) {
if(set.add(c)==false) {
System.out.println(c);
}
}
}
public static void main(String[] args) {
duplicateString("Java ashishj ");
}
}
It will print a a s h
. But I want a s h
using only Set
interface.
Upvotes: 1
Views: 1987
Reputation: 56
Use one more set to store the duplicate element and print the element. Try like this:
public static void duplicateString(String str) {
str=str.replaceAll(" ","");
char[] cArray = str.toCharArray();
Set<Character> set = new HashSet<Character>();
Set<Character> set1 = new HashSet<Character>();
for(char c:cArray) {
if(set.add(c)==false) {
if(set1.add(c) == true)
System.out.println(c);
}
}
}
Upvotes: 1
Reputation: 132380
It's not entirely clear to me what's required by "using only the Set
interface" but I'll assume that this means that the duplicate characters are to be returned in a Set
. There are several ways of doing this. The first is the straightforward loop over the chars of the input string. It takes advantage of the feature of Set.add
which returns true
if the set was modified and false
if it wasn't; that means that an add
operation that returns false
is a duplicate.
static Set<Character> dups0(String input) {
Set<Character> dups = new HashSet<>();
Set<Character> seen = new HashSet<>();
for (char ch : input.toCharArray()) {
if (! seen.add(ch)) {
dups.add(ch);
}
}
return dups;
}
There's a streamy way to do this, which is essentially the same thing expressed in stream form:
static Set<Character> dups1(String input) {
Set<Character> seen = new HashSet<>();
return input.chars()
.mapToObj(ch -> (char)ch)
.filter(ch -> !seen.add(ch))
.collect(toSet());
}
Some people might find this distasteful, as its filter operation performs side effects. In addition, if this is run in parallel, the result would need to be something like a ConcurrentHashMap.newKeySet
.
An alternative is to generate a frequency table of characters and remove all the entries that occur just once:
static Set<Character> dups2(String input) {
Map<Character, Long> map = input.chars()
.mapToObj(i -> (char)i)
.collect(groupingBy(ch -> ch, HashMap::new, counting()));
map.values().removeIf(v -> v == 1);
return map.keySet();
}
Note that this uses a collections bulk mutation operation on the values-collection view of the map. To ensure that the map is mutable, I've used the three-arg overload of groupingBy
to specify the map's implementation type.
If you don't like mutation, there's a pure-streams way to do this:
static Set<Character> dups3(String input) {
Map<Character, Long> map = input.chars()
.mapToObj(i -> (char)i)
.collect(groupingBy(ch -> ch, counting()));
return map.entrySet().stream()
.filter(entry -> entry.getValue() > 1)
.map(Map.Entry::getKey)
.collect(toSet());
}
Upvotes: 1
Reputation: 1374
Try that:
public static void duplicateString(String str) {
Set<Character> firstTime = new HashSet<Character>();
Set<Character> reported = new HashSet<Character>();
char[] cArray = str.toCharArray();
for(char c:cArray) {
if (!firstTime.contains(c)) {
firstTime.add(c);
continue;
}
if (reported.contains(c)) { continue; }
reported.add(c);
System.out.println(c);
}
}
Thanks to Holger's suggestion I ran some tests:
- add: 52443260ns for 10000000 operations
- contains: 28209745ns for 10000000 operations
Therefore the code above although not shorter is fastest.
Upvotes: 1
Reputation: 585
You can make use of String.split() here. This method splits the string up into an array of strings based on the regular expression provided. We will use a "" because we want to split the string after every single character, and then input the results into a stream.
public static void duplicateString( String str ) {
// collect all characters in a map, whose String value is the character and whose key value is the count of occurrences in the string
Map<String,Long> charCountMap = Arrays.stream( str.split( "" ) )
.filter( charInString -> !charInString.equals( " " ) ) // don't want spaces
.collect( Collectors.groupingBy( Function.identity(), Collectors.counting() ) );
charCountMap.entrySet()
.stream()
.filter( entrySet -> entrySet.getValue() > 1 ) // filter out occurrences that are one or less
.forEach( entrySet -> System.out.println( String.format( "Char %s appeared %d times", entrySet.getKey(), entrySet.getValue() ) ) );
}
Upvotes: 0
Reputation: 6168
All you need to do is use the add()
method of the Set
class to tell you if the thing being inserted (added) is already part of the set. When the function returns false
it means the current "thing" being added is a duplicate. Then, add that to a Set
of duplicates. This way, items duplicated more than once, will only show once in the new set. Lastly, to conserve the order, you may want to use a LinkedHashSet
to store duplicates.
public class TestDups {
public static void main (String[] args) {
String str = "Java ashishj ";
Set<Byte> myset = new TreeSet<>();
Set<Character> dups = new LinkedHashSet<>();
for (byte c: str.getBytes() ) {
if (!myset.add(c)) {
dups.add((char)c);
}
}
dups.stream().forEach(System.out::print);
}
}
The output of the code above is "ash ". Notice the white space at the end since the original String contains two spaces (between words and at the end).
Upvotes: 1
Reputation: 23
public static void main(String[] args) {
String s = "Javaashishj";
char[] cArray = s.toCharArray();
Set<Character> set = new HashSet<Character>();
for (char c : cArray) {
if (!set.contains(c)) {
set.add(c);
System.out.println(c);
}
}
}
Upvotes: 0
Reputation: 11
Check this program
public static void duplicateString(String str) {
char[] cArray = str.replaceAll("\\s+", "").toCharArray();
Set<Character> set = new HashSet<Character>();
Set<Character> alreadyExistingSet = new HashSet<Character>();
for (char c : cArray) {
if (set.add(c) == false && alreadyExistingSet.add(c) == true) {
System.out.print(c);
}
}
}
Upvotes: 1