首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >按字母顺序对集合进行排序,集合中的字母以逗号分隔

按字母顺序对集合进行排序,集合中的字母以逗号分隔
EN

Stack Overflow用户
提问于 2018-11-19 06:55:49
回答 4查看 215关注 0票数 4
代码语言:javascript
运行
复制
public static void main(String[] args) throws IOException
{

    HashSet set = new HashSet<String>();

    set.add("{}");
    set.add("{a}");
    set.add("{b}");
    set.add("{a, b}");
    set.add("{a, c}");

    sortedSet(set);
}

public static void sortedSet(HashSet set)
{
    List<String> setList = new ArrayList<String>(set);
    List<String> orderedByAlpha = new ArrayList<String>(set);

    //sort by alphabetical order
    orderedByAlpha = (List<String>) setList.stream()
        .sorted((s1, s2) -> s1.compareToIgnoreCase(s2))
        .collect(Collectors.toList());
    System.out.println(orderedByAlpha);
}

我尝试按字母顺序排序,但得到的输出如下:

代码语言:javascript
运行
复制
[{a, b}, {a, c}, {a}, {b}, {}]

但它应该是:

代码语言:javascript
运行
复制
[{a}, {a, b}, {a, c}, {b}, {}]
EN

回答 4

Stack Overflow用户

发布于 2018-11-19 07:13:15

您的输出与您的代码不匹配。您正在显示二维数组列表,但转换为一维数组列表没有任何意义。

代码语言:javascript
运行
复制
public static void main(String[] args)
{
    test(Arrays.asList("a", "d", "f", "a", "b"));
}

static void test(List<String> setList)
{
    List<String> out = setList.stream().sorted((a, b) -> a.compareToIgnoreCase(b)).collect(Collectors.toList());
    System.out.println(out);
}

这是对一维数组的正确排序,所以你是对的。

您可能需要实现自己的比较器来比较二维数组列表,以便对它们进行排序。

票数 0
EN

Stack Overflow用户

发布于 2018-11-19 07:23:00

与其将源代码作为List<String>,我建议您将其作为List<Set<String>>

代码语言:javascript
运行
复制
List<Set<String>> setList = new ArrayList<>();
setList.add(new HashSet<>(Arrays.asList("a","b")));
setList.add(new HashSet<>(Arrays.asList("a","c")));
setList.add(new HashSet<>(Collections.singletonList("a")));
setList.add(new HashSet<>(Collections.singletonList("b")));
setList.add(new HashSet<>());

然后将以下比较器与映射操作一起应用,以产生预期的结果:

代码语言:javascript
运行
复制
List<String> result = 
     setList.stream()
         .sorted(Comparator.comparing((Function<Set<String>, Boolean>) Set::isEmpty)
                        .thenComparing(s -> String.join("", s),
                        String.CASE_INSENSITIVE_ORDER))
         .map(Object::toString)
         .collect(Collectors.toList());

打印结果如下:

代码语言:javascript
运行
复制
[[a], [a, b], [a, c], [b], []]

请注意,当前的结果是一个字符串列表,其中每个字符串都是给定集合的字符串表示。但是,如果您希望结果是一个List<Set<String>>,那么只需删除上面的map操作。

编辑:

根据你最初的想法,我设法得到了一个有效的解决方案……

因此,首先,您需要一个全新的比较器,而不仅仅是(s1, s2) -> s1.compareToIgnoreCase(s2),因为它还不够。

给定输入:

代码语言:javascript
运行
复制
Set<String> set =  new HashSet<>();

set.add("{}");
set.add("{a}");
set.add("{b}");
set.add("{a, b}");
set.add("{a, c}");

和下面的流管道:

代码语言:javascript
运行
复制
List<String> result = set.stream()
            .map(s -> s.replaceAll("[^A-Za-z]+", ""))
            .sorted(Comparator.comparing(String::isEmpty)
                    .thenComparing(String.CASE_INSENSITIVE_ORDER))
            .map(s -> Arrays.stream(s.split(""))
                            .collect(Collectors.joining(", ", "{", "}")))
            .collect(Collectors.toList());

然后我们会得到一个结果:

代码语言:javascript
运行
复制
[{a}, {a, b}, {a, c}, {b}, {}]
票数 0
EN

Stack Overflow用户

发布于 2018-11-21 23:14:36

嗯,正如@Aomine和@Holger已经提到的,你需要一个自定义的比较器。

但是我觉得他们的解决方案看起来是过度设计的。您不需要任何代价高昂的操作,如splitsubstring

  • String.substring会创建一个新的String对象并在幕后调用System.arraycopy(),而
  • String.split的开销会更大。它遍历您的字符串并多次调用String.substring。此外,它还创建了一个ArrayList来存储所有子字符串。如果子字符串的数量足够大,那么您的ArrayList将需要扩展其容量(可能不止一次),从而导致另一次System.arraycopy().

调用

对于您的简单情况,我会稍微修改一下内置String.compareTo方法的代码:

代码语言:javascript
运行
复制
Comparator<String> customComparator =
            (s1, s2) -> {
                int len1 = s1.length();
                int len2 = s2.length();

                if (len1 == 2) return 1;
                if (len2 == 2) return -1;

                int lim = Math.min(len1, len2) - 1;

                for (int k = 1; k < lim; k++) {
                    char c1 = s1.charAt(k);
                    char c2 = s2.charAt(k);
                    if (c1 != c2) {
                        return c1 - c2;
                    }
                }
                return len1 - len2;
            };

它将比较复杂度为O(n)的字符串,其中n是较短字符串的长度。同时,它既不会创建任何新对象,也不会执行任何阵列复制。

可以使用Stream API实现相同的比较器

代码语言:javascript
运行
复制
Comparator<String> customComparatorUsingStreams =
            (s1, s2) -> {
                if (s1.length() == 2) return 1;
                if (s2.length() == 2) return -1;
                return IntStream.range(1, Math.min(s1.length(), s2.length()) - 1)
                        .map(i -> s1.charAt(i) - s2.charAt(i))
                        .filter(i -> i != 0)
                        .findFirst()
                        .orElse(0);
            };

您可以像这样使用您的自定义比较器:

代码语言:javascript
运行
复制
List<String> orderedByAlpha = setList.stream()
                                     .sorted(customComparatorUsingStreams)
                                     .collect(Collectors.toList());
System.out.println(orderedByAlpha);
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53366258

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档