为了账号安全,请及时绑定邮箱和手机立即绑定

字符串和数字的范围分组列表

字符串和数字的范围分组列表

呼唤远方 2023-06-04 15:07:00
我有一个看起来像这样的列表String[] lst = {BB,2,1,3,AA,DD,A3,A1,EE,A2,4);我需要对该列表进行分组和排列,但遇到了麻烦,因此需要找到类似的东西结果:(1-4),(A1-A3),(AA-BB),(DD-EE)我想出的代码是这样的Map<Character, List<String>> collect;collect = Arrays.stream(str).flatMap(s -> Stream.of(s.split("[^a-zA-Z0-9]"))).filter(s -> !s.trim().isEmpty()).sorted().collect(Collectors.groupingBy(s -> s.charAt(0)));但它按第一个字母分组,这意味着 AA 与 A1-A3 分组,依此类推。它不是那么微不足道的分组,我将不胜感激任何帮助。
查看完整描述

3 回答

?
慕尼黑8549860

TA贡献1818条经验 获得超11个赞

这是我的解决方案。

AdjacentAwareComparator只要它在其价值空间中正确实施,这将适用于任何给定的情况。以下comparator是您定义的值空间。

如果您不需要所有元素,您可以很容易地getRanges接受一个而不是数组,或者只存储范围的第一个和最后一个:List

import static java.lang.Character.isDigit;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Comparator;

import java.util.List;


public class Main {


    /**

     * Marker interface.

     * 

     * Implementors MUST adhere to all contracts of Comparator, and MUST return -1 or 1 if and only if

     * the compared values are adjacent to one another within the set of all possible values.

     */

    @FunctionalInterface public interface AdjacentAwareComparator<T> extends Comparator<T> {};


    /**

     * Assumes the input is valid in the defined value space.

     * 

     * Sort order: Digit (natural), Alpha+Digit (by alpha, then by digit), Alpha+Alpha (natural)

     */

    private static AdjacentAwareComparator<String> comparator = (x, y) -> {

        // uses 2 and -2 to compare values as non-adjacent

        if (x == null) return (y == null) ? 0 : -2;

        if (y == null) return 2;

        // both are not null...


        if (x.isEmpty()) return y.isEmpty() ? 0 : -2;

        if (y.isEmpty()) return 2;

        // both are at least length 1...


        char x1 = x.charAt(0), y1 = y.charAt(0);

        if (isDigit(x1)) return isDigit(y1) ? (x1 - y1) : -2;

        if (isDigit(y1)) return 2;

        // both start with letters...


        int d1 = x1 - y1; // delta between first chars

        char x2 = x.charAt(1), y2 = y.charAt(1);

        if (isDigit(x2)) return isDigit(y2) ? ((d1 == 0) ? (x2 - y2) : (d1 * 2)) : -2;

        if (isDigit(y2)) return 2;


        // the strings are double letters (eg. 'AA' and 'BB')

        return d1;

    };


    public static <T> List<List<T>> getRanges(T[] arr, AdjacentAwareComparator<T> comp) {

        if (arr.length == 0) {

            return new ArrayList<>();

        }

        List<List<T>> ranges = new ArrayList<>();

        List<T> range = new ArrayList<>();


        // sort using the custom Comparator

        Arrays.sort(arr, comp);

        T prev = arr[0];

        range.add(prev);


        // iterate through the sorted array

        for (int i = 1; i < arr.length; i++) {

            T curr = arr[i];

            int d = comp.compare(prev, curr);

            if (d < -1 || 1 < d) {

                // prev and curr are not adjacent nor equal, so start a new range

                ranges.add(range);

                range = new ArrayList<>();

            }

            range.add(curr);

            prev = curr;

        }

        ranges.add(range);

        return ranges;

    }


    public static void main(String[] args) {

        String[] arr = {"4","1","BB","ZZ","A1","5","A5","FF","3","B2","A2","B1","AA"};

        for (List<String> range : getRanges(arr, comparator)) {

            System.out.println("{" + String.join(", ", range) + "}");

        }

        // prints:

        //   {1}

        //   {3, 4, 5}

        //   {A1, A2}

        //   {A5}

        //   {B1, B2}

        //   {AA, BB}

        //   {FF}

        //   {ZZ}

    }

}


查看完整回答
反对 回复 2023-06-04
?
jeck猫

TA贡献1909条经验 获得超7个赞

正如另一位用户在评论中提到的那样,推出自己的解决方案并不简单。要解决此特定问题,您可以执行类似的操作


    String[] str = {"BB","2","1","3","AA","DD","A3","A1","EE","A2","4"};

    Map<String, List<String>> collect;


    collect = Arrays.stream(str)

            .flatMap(s -> Stream.of(s.split("[^a-zA-Z0-9]")))

            .filter(s -> !s.trim().isEmpty())

            .sorted()

            .collect(Collectors.groupingBy(s -> {

                final StringBuilder groupKey = new StringBuilder();

                char first = s.charAt(0);

                if (Character.isAlphabetic(first)) {

                    if (first >= 'D') {

                        groupKey.append("ALPHA-HIGH");

                    } else {

                        groupKey.append("ALPHA-LOW");

                    }

                } else {

                    groupKey.append("NON-ALPHA");

                }

                if (s.length() == 2) {

                    char second = s.charAt(1);

                    if (Character.isAlphabetic(second)) {

                        if (first >= 'D') {

                            groupKey.append("_ALPHA-HIGH");

                        } else {

                            groupKey.append("_ALPHA-LOW");

                        }

                    } else {

                        groupKey.append("_NON-ALPHA");

                    }

                }

                return groupKey.toString();

            }));

这将为您提供所需的输出。请注意,使用键 (String) 而不是单个字符。


这里发生了什么?您有很多不同的可能组,我将其视为两个宏组:字母组和非字母组。在你的情况下,非字母的东西是数字。长度为 2 的字符串可以将第二个字符作为字母或数字。如果 alpha 字符大于D或等于,则被认为是“高”。


输出


四组:


NON-ALPHA: {1, 2, 3, 4}

ALPHA-LOW_NON-ALPHA: {A1, A2, A3}

ALPHA-HIGH_ALPHA-HIGH: {DD, EE}

ALPHA-LOW_ALPHA-LOW: {AA, BB}


查看完整回答
反对 回复 2023-06-04
?
繁星coding

TA贡献1797条经验 获得超4个赞

要构建这样的连续组,您首先需要定义一个函数,该函数采用两个项目来识别它们是否相互跟随,即按连续顺序排列。例如,“1”之后是“2”,但不是“3”或“A”;在您的示例中,“AA”后跟“BB”。有了这样的功能,您可以遍历排序列表并比较相邻的项目来决定是打开一个组、关闭它还是单独打印一个项目。


我会调用这样的函数follows(String a, String b)。然后构建组的算法非常简单:


static String printGroups(String[] items) {

  Arrays.sort(items);      // strictly saying, sorting order must be consistent with `follows`

  boolean open = false;    // a group is open currently

  StringBuilder result = new StringBuilder();

  for (int i = 0; i < items.length; ++i) {

    if (!open && i > 0) {

      result.append(',');

    }

    if (i < items.length - 1 && follows(items[i], items[i + 1])) {

      if (!open) {

        // open a group

        result.append('(').append(items[i]).append('-');

        open = true;

      }

    } else if (open) {

      // close the group

      result.append(items[i]).append(')');

      open = false;

    } else {

      // print a standalone item

      result.append(items[i]);

    }

  }

  return result.toString();

}

该功能已根据您的示例进行了调整(看起来很糟糕,您可以使用 java 流或其他任何方式follows使其更清晰/可读)-StringUtils


static boolean follows(String a, String b) {

    if (a.length() != b.length() && a.length() == 0) {

        return false;

    }

    // AAA -> BBB

    if (allSame(a) && allSame(b) && (b.charAt(0) - a.charAt(0) == 1)) {

        return true;

    }

    // ABC1 -> ABC2

    // finding common prefix

    int p = 0;

    while (p < a.length() && a.charAt(p) == b.charAt(p)) {

        ++p;

    }

    return (p == a.length() - 1) && (b.charAt(p) - a.charAt(p) == 1);

}


static boolean allSame(String chars) {

    char s = chars.charAt(0);

    return chars.chars().allMatch(c -> s == c);

}

之后,您只需将文本拆分为项目并提要:


printGroups("BB,2,1,3,AA,DD,A3,A1,EE,A2,4".split(","));  // (1-4),(A1-A3),(AA-BB),(DD-EE)



查看完整回答
反对 回复 2023-06-04
  • 3 回答
  • 0 关注
  • 121 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信