简体   繁体   English

按字典顺序排序数组列表,忽略整数

[英]Sort Array List lexicographically ignoring integers

I have this code.我有这个代码。 I want to order a list of strings.我想订购一个字符串列表。 Every item in the list consists of a three word sentence.列表中的每个项目都由一个三个单词的句子组成。 I want to ignore the first word and sort the sentence lexicographically with the 2nd and 3rd words.我想忽略第一个单词并用第二个和第三个单词按字典顺序对句子进行排序。 If the 2nd or 3rd words contain an integer, I want to ignore sorting them but add them to the end of the list.如果第二个或第三个单词包含 integer,我想忽略对它们进行排序,但将它们添加到列表的末尾。 For example: (19th apple orange, 17th admin 7th, 19th apple table) should be sorted in the list as (19th apple orange, 19th apple table, 17th admin 7th) So far my code only ignores the first word and sort lexicographically the rest of the lists例如: (19th apple orange, 17th admin 7th, 19th apple table) 应在列表中排序为 (19th apple orange, 19th apple table, 17th admin 7th) 到目前为止,我的代码仅忽略第一个单词并按字典顺序排序 rest名单中的

public static List<String> sortOrders(List<String> orderList) {
     // Write your code here
    Collections.sort( orderList,
    (a, b) -> a.split(" *", 2)[1].compareTo( b.split(" *", 2)[1] )
    );
    
    return orderList;
}

In your compare method check for numbers first and then strings.在您的比较方法中,首先检查数字,然后检查字符串。 You just have to add code to the steps you described:您只需将代码添加到您描述的步骤中:

Here's a pseudo code of what you described这是您描述的伪代码

...
(a,b) -> {
    // Every item in the list consists of a three word sentence.
    var awords = a.split(" ")
    var bwords = a.split(" ")
   
    // I want to ignore the first word
    var as = awords[1] + " " awords[2]
    var bs ...  
    //  and sort the sentence lexicographically with the 2nd and 3rd words.
    var r = as.compareTo(bs) 
    
    // If the 2nd or 3rd words contain an integer, I want to ignore sorting them but add them to the end of the list
    if ( as.matches(".*\\d.*) ) {
        return -1
     } else { 
        return r
     }

}
...

It's not clear what to do if both have numbers, eg a 1 a vs a 1 b , but that's something you have to clarify.如果两者都有数字,例如a 1 aa 1 b ,尚不清楚该怎么办,但这是您必须澄清的事情。

So basically you just have to go, divide each of the statements in your problem and add some code that solves it (like the example below )所以基本上你只需要 go,划分问题中的每个语句并添加一些解决它的代码(如下例所示)

You might notice there are some gaps (like what to do if two of them have strings).您可能会注意到存在一些差距(例如如果其中两个有字符串该怎么办)。 Once you have a working solution you can clean it up.一旦你有了一个可行的解决方案,你就可以清理它。

Another alternative with a similar idea另一种具有类似想法的替代方案

var as = a.substring(a.indexOf(" ")) // "a b c" -> "b c"
var bs = b.substring(b.indexOf(" ")) // "a b c" -> "b c"
return as.matches("\\d+") ? -1 : as.compareTo(bs);

Remember the compare(T,T) method returns < 0 if a is "lower" than b, so if a has numbers, it will always be "higher" thus should return 1 , if b has numbers then a will be "lower", thus it should return -1 , otherwise just compare the strings记住compare(T,T)方法返回 < 0 如果 a “低于” b,所以如果a有数字,它总是“高”,因此应该返回1 ,如果b有数字,那么a将“低” ,因此它应该返回-1 ,否则只比较字符串

Here's the full program:这是完整的程序:

import java.util.*;

public class Sl {

  public static void main(String ... args ) {

    var list = Arrays.asList("19th apple orange", "17th admin 7th", "19th apple table");

    Collections.sort(list, (a, b) -> {
      // just use the last two words
      var as = a.substring(a.indexOf(" "));
      var bs = b.substring(b.indexOf(" "));

      // if a has a number, will always be higher
      return as.matches(".*\\d+.*") ? 1 
         // if b has a number, a will always be lower
         : bs.matches(".*\\d+.*") ? -1 
         // if none of the above, compare lexicographically the strings
         : as.compareTo(bs);
    });

    System.out.println(list);
  }
}

If you aren't careful, you will get an error such as Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!一不小心,就会得到Exception in thread "main" java.lang.IllegalArgumentException: Comparison method violates its general contract!

In order to prevent that you can do it as follows by creating a comparator that parses the string and checks the second and third elements for integers.为了防止发生这种情况,您可以通过创建一个解析字符串并检查第二个和第三个元素的整数的比较器来执行以下操作。 If the first element has not integers but the second one does, it will be sent to the bottom since the second one is considered greater by returning a 1. But the next condition must only check on the second element and return a -1 indicating that it is smaller than the one so gain, it goes to the bottom of the list.如果第一个元素没有整数但第二个元素有,它将被发送到底部,因为通过返回 1 认为第二个元素更大。但是下一个条件必须只检查第二个元素并返回 -1 表示它比增益小,它排在列表的底部。

public static List<String> sortOrders(List<String> orderList) {
    Comparator<String> comp = (a, b) -> {
        String[] aa = a.split("\\s+", 2);
        String[] bb = b.split("\\s+", 2);
        boolean aam = aa[1].matches(".*[0-9]+.*");
        boolean bbm = bb[1].matches(".*[0-9]+.*");
        
        return aam && !bbm ? 1 : bbm ? -1 :
           aa[1].compareTo(bb[1]);
    };
    
    return orderList.stream().sorted(comp).toList();    
}

If you want to preserve your original data, use the above.如果要保留原始数据,请使用上述方法。 If you want to sort in place, then apply the Comparator defined above and use Collections.sort(data, comp) .如果要就地排序,请应用上面定义的比较器并使用Collections.sort(data, comp)

I have tested this extensively using the following data generation code which generated random strings meeting your requirements.我已经使用以下数据生成代码对此进行了广泛测试,该代码生成了满足您要求的随机字符串。 I suggest you test any answers you get (including this one) to ensure it satisfies your requirements.我建议你测试你得到的任何答案(包括这个),以确保它满足你的要求。

String letters = "abcdefghijklmnopqrstuvwxyz";
Random r = new Random(123);
List<String> data = r.ints(200000, 1, 100).mapToObj(i -> {
    StringBuilder sb = new StringBuilder();
    boolean first = r.nextBoolean();
    boolean second = r.nextBoolean();
    int ltr = r.nextInt(letters.length());
    String fstr = letters.substring(ltr,ltr+1);
    ltr = r.nextInt(letters.length());
    String sstr = letters.substring(ltr,ltr+1);
    sb.append(fstr).append(first ? ltr : "").append(" ");
    sb.append(fstr);
    if (first) {
        sb.append(r.nextInt(100));
    }
    sb.append(" ").append(sstr);
    
    if (!first && second) {
        sb.append(r.nextInt(100));
    }
     
    return sb.toString();
}).collect(Collectors.toCollection(ArrayList::new));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM