17

I'm facing a problem right now. In one of my program, I need to remove strings with same characters from an Array. For eg. suppose,

I have 3 Arrays like,

String[] name1 = {"amy", "jose", "jeremy", "alice", "patrick"};
String[] name2 = {"alan", "may", "jeremy", "helen", "alexi"};
String[] name3 = {"adel", "aron", "amy", "james", "yam"};

As you can see, there is a String amy in the name1 array. Also, I have strings like may, amy and yam in the next two arrays. What I need is that, I need a final array which does not contain these repeated Strings. I just need only one occurrence: I need to remove all permutations of a name in the final array. That is the final array should be:

String[] finalArray={"amy", "jose", "alice", "patrick","alan", "jeremy", "helen", "alexi","adel", "aron", "james"}

(The above array removed both yam, may, and only includes amy).

What i have tried so far, using HashSet, is as below

String[] name1 = {"Amy", "Jose", "Jeremy", "Alice", "Patrick"};
String[] name2 = {"Alan", "mAy", "Jeremy", "Helen", "Alexi"};
String[] name3 = {"Adel", "Aaron", "Amy", "James", "Alice"};
Set<String> letter = new HashSet<String>();
for (int i = 0; i < name1.length; i++) {
    letter.add(name1[i]);
}
for (int j = 0; j < name2.length; j++) {
    letter.add(name2[j]);
}
for (int k = 0; k < name3.length; k++) {
    letter.add(name3[k]);
}
System.out.println(letter.size() + " letters must be sent to: " + letter);

But, the problem with this code is that, it just removes multiple occurences of the same string. Is there any other alternative? Any help is very much appreciated.

0

4 Answers 4

10

You can sort the character array of the String (str.toCharArray ()) and create a new String from the sorted array to get a "canonical" representation of a String.

Then you can add these Strings to a Set, and check for each String whether the canonical representation is already in the Set.

Set<String> letter = new HashSet<String>();
for (int i = 0; i < name1.length; i++) {
    char[] chars = name1[i].toCharArray();
    Arrays.sort(chars);
    letter.add(new String(chars));
}
for (int j = 0; j < name2.length; j++) {
    char[] chars = name2[j].toCharArray();
    Arrays.sort(chars);
    letter.add(new String(chars));
}
for (int k = 0; k < name3.length; k++) {
    char[] chars = name3[k].toCharArray();
    Arrays.sort(chars);
    letter.add(new String(chars));
}

EDIT : I changed the Set<char[]> to Set<String>, since arrays don't override hashCode and equals, so HashSet<char[]> wouldn't work.

Sign up to request clarification or add additional context in comments.

15 Comments

Great.. :) Thinks like a nice solution..Thankyou.. :) will just try and update you soon...
One more doubt..for eg, if the contents of the string array were like, A={"1 2 3 4","5 6 7 8","3 4 2 1"}, then how could this e done?
@Lal Actually, you should convert the char[] back to String before putting it in the Set, since arrays don't override equals and hashCode
@Lal That depends how you wish to treat the empty spaces. If you want to ignore them, use letter.add(new String(Arrays.sort(name2[j].toCharArray())).trim());
@Lal The results contains Jeemry instead of Jeremy. OK?
|
7

TreeSet allows us to give a comparator. See whether this helps. For keeping the count use a TreeMap.

package empty;

import java.util.Arrays;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

public class RemoveDuplicateStrings {

    public static void main(String[] args) {
        String[] name1 = { "amy", "jose", "jeremy", "alice", "patrick" };
        String[] name2 = { "alan", "may", "jeremy", "helen", "alexi" };
        String[] name3 = { "adel", "aron", "amy", "james", "yam" };

        Comparator<String> comparator = new Comparator<String>() {
            @Override public int compare(String o1, String o2) {
                System.out.println("Compare(" + o1 + "," + o2 + ")");
                char[] a1 = o1.toCharArray();
                Arrays.sort(a1);
                char[] a2 = o2.toCharArray();
                Arrays.sort(a2);
                return new String(a1).compareTo(new String(a2));
            }
        };
        Set<String> set = new TreeSet<String>(comparator);

        for (String name : name1) {
            set.add(name);
        }
        for (String name : name2) {
            set.add(name);
        }
        for (String name : name3) {
            set.add(name);
        }

        String[] result = set.toArray(new String[set.size()]);
        System.out.println(Arrays.asList(result));

        // Using TreeMap to keep the count.

        TreeMap<String, Integer> map = new TreeMap<String, Integer>(comparator);

        addAll(name1, map);
        addAll(name2, map);
        addAll(name3, map);

        System.out.println(map);
    }

    private static void addAll(String[] names, TreeMap<String, Integer> map) {
        for (String name : names) {
            if (map.containsKey(name)) {
                int n = map.get(name);
                map.put(name, n + 1);
            } else
                map.put(name, 1);
        }
    }
}

3 Comments

Rather slow though - it will sort the String for each comparison, and there will be quite a few comparisons. You should create "normalised" sets of the data then combine.
@KDM Is there any possibility of getting the count of occurences of each string from your answer?
Use a TreeMap instead of TreeSet. I am modifying the answer to add it.
2

In line with kdm:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class RemoveDuplicateString {

    private static boolean add(Set<String> keySet, String s){
        char[] sortCharacters = s.toCharArray();
        Arrays.sort(sortCharacters);
        return keySet.add(new String(sortCharacters));
    }

    private static void check(Set<String> keySet, String []names, List<String> result){
        for (String name : names) {
            if (add(keySet, name)){
                result.add(name);
            }
        }
    }

    public static void main(String[] args) {
        String[] name1 = {"amy", "jose", "jeremy", "alice", "patrick"};
        String[] name2 = {"alan", "may", "jeremy", "helen", "alexi"};
        String[] name3 = {"adel", "aron", "amy", "james", "yam"};
        Set<String> keySet = new HashSet<String>();
        List<String> result = new ArrayList<String>();
        check(keySet, name1, result);
        check(keySet, name2, result);
        check(keySet, name3, result);
        System.out.println(result);
    }
}

Comments

1

An alternative, Java 8, solution.

1) Create a Map<String, List<String> with the normalised form and then all the seen different forms

public static Map<String, List<String>> groupNormalised(final String[]... input) {
    return Arrays.stream(input)
            .flatMap(Arrays::stream)
            .collect(Collectors.groupingBy(s -> {
                char[] c = s.toCharArray();
                Arrays.sort(c);
                return new String(c);
            }));
}

Example:

Map<String, List<String>> grouped = groupNormalised(name1, name2, name3);        
grouped.forEach((k, v) -> System.out.printf("%s appears as %s%n", k, v));

Output:

eejmry appears as [jeremy, jeremy]
aceil appears as [alice]
eehln appears as [helen]
ejos appears as [jose]
adel appears as [adel]
aeilx appears as [alexi]
acikprt appears as [patrick]
aejms appears as [james]
amy appears as [amy, may, amy, yam]
anor appears as [aron]
aaln appears as [alan]

2) Process the Map to extract the data that you want

Now you have a choice, you can either create a Set of the normalised forms:

final Set<String> normalisedForms = grouped.keySet();

Or you can create a Set of the first encounters:

final Set<String> first = grouped.values().stream()
        .map(c -> c.iterator().next())
        .collect(toSet());

Or as an array:

final String[] first = grouped.values().stream()
        .map(c -> c.iterator().next())
        .toArray(String[]::new);

2 Comments

Might be a working solution..but i was looking for a solution in jdk7..thanks for the response..
@Lal unless you have good reason to stick with Java 7, I would suggest that you begin upgrading to Java 8. It's been out for over a year...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.