【问题标题】:Remove Strings with same characters in a String Array删除字符串数组中具有相同字符的字符串
【发布时间】:2015-09-08 19:48:48
【问题描述】:

我现在面临一个问题。在我的一个程序中,我需要从数组中删除具有相同字符的字符串。例如。假设,

我有 3 个类似的数组,

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

如您所见,name1 数组中有一个字符串 amy。另外,我在接下来的两个数组中有mayamyyam 之类的字符串。我需要的是,我需要一个不包含这些重复字符串的最终数组。我只需要出现一次:我需要删除最终数组中名称的所有排列。那就是最终的数组应该是:

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

(上面的数组删除了 yam,may,并且只包括 amy)。

到目前为止,我使用HashSet 所做的尝试如下

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);

但是,这段代码的问题在于,它只是删除了同一字符串的多次出现。还有其他选择吗?非常感谢任何帮助。

【问题讨论】:

    标签: java arrays string duplicate-removal


    【解决方案1】:

    您可以对字符串 (str.toCharArray ()) 的字符数组进行排序,并从排序后的数组中创建一个新字符串,以获得字符串的“规范”表示。

    然后您可以将这些字符串添加到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));
    }
    

    编辑:我将Set&lt;char[]&gt; 更改为Set&lt;String&gt;,因为数组不会覆盖hashCodeequals,所以HashSet&lt;char[]&gt; 不起作用。

    【讨论】:

    • 太棒了.. :) 认为是一个不错的解决方案..谢谢.. :) 会尽快尝试更新您...
    • 还有一个疑问..例如,如果字符串数组的内容是这样的,A={"1 2 3 4","5 6 7 8","3 4 2 1"} ,那这e怎么办?
    • @Lal 实际上,您应该在将 char[] 放入 Set 之前将其转换回 String,因为数组不会覆盖 equals 和 hashCode
    • @Lal 这取决于您希望如何处理空格。如果您想忽略它们,请使用 letter.add(new String(Arrays.sort(name2[j].toCharArray())).trim());
    • @Lal 结果包含Jeemry 而不是Jeremy。好吗?
    【解决方案2】:

    TreeSet 允许我们提供一个比较器。看看这是否有帮助。为了保持计数,请使用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);
            }
        }
    }
    

    【讨论】:

    • 很好的答案..工作得很好..谢谢.. :)
    • 虽然比较 slow - 它会为每个比较对String 进行排序,并且会有很多比较。您应该创建“标准化”数据集,然后合并。
    • @KDM 是否有可能从您的答案中获取每个字符串的出现次数?
    • 使用 TreeMap 而不是 TreeSet。我正在修改答案以添加它。
    【解决方案3】:

    符合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);
        }
    }
    

    【讨论】:

      【解决方案4】:

      另一种 Java 8 解决方案。

      1) 使用规范化形式创建Map&lt;String, List&lt;String&gt;,然后创建所有看到的不同形式

      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);
                  }));
      }
      

      例子:

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

      输出:

      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)处理Map以提取您想要的数据

      现在您有一个选择,您可以创建一个Set 的规范化形式:

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

      或者您可以创建第一次相遇的Set

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

      或者作为一个数组:

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

      【讨论】:

      • 可能是一个可行的解决方案..但我正在寻找 jdk7 中的解决方案..感谢您的回复..
      • @Lal 除非您有充分的理由坚持使用 Java 7,否则我建议您开始升级到 Java 8。它已经推出一年多了...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 2012-05-09
      • 1970-01-01
      • 2020-09-14
      • 1970-01-01
      • 2021-09-03
      • 1970-01-01
      相关资源
      最近更新 更多