简体   繁体   中英

Simple way to parse numbers as strings while sorting with Java streams?

I have a list of objects that contain values stored as strings but are actually numbers and I'm trying to find a way to parse strings to integers within a Java stream to sort them numerically. Here's what I got so far.

List<SearchResultObject> returnedValues = doTheSearchMethod();
returnedValues = returnedValues
.stream()
.sorted(Comparator.comparing(SearchResultObject::getNumber))
.collect(Collectors.toList());

As of right now this kind of works, but the problem is that because those numbers are actually strings, it sorts the numbers lexicographically, not numerically. Is there a way to incorporate parsing into the stream? All numbers are padded to be the same size.

3356001017053000000000000
3356001017002000000000000
3356001017004000000000000
3356001017026000000000000
5101004003020000000000000
4123000006002510000000000
4758000005010000000000000

use comparingLong and then parse long. the numbers are too large for integers.

returnedValues.sort(Comparator.comparingLong(sro->Long.parseLong(sro.getNumber())));

For just sorting you don't need stream, just use custom Comparator using lambda expression

Comparator<SearchResultObject> c = Comparator.comparingLong(s->Long.parseLong(s.getNumber()));

And then use Collections.sort method

Collections.sort(returnedValues,c);

You don't need to use Streams API for sorting the list, you can directly use sort() method from the List interface. You just need to ensure that you provide a proper comparator to the sort() method.

As you mentioned, you can directly use:

Comparator.comparing(SearchResultObject::getNumber)

comparator to compare the strings.

However, as you need the list to be sorted by comparing the Integer/Long, you can use the following:

  1. For Integer:

    list.sort(Comparator.comparingInt(s ->Integer.parseInt(s.getNumber())));

  2. For Long:

    list.sort(Comparator.comparingLong(s ->Long.parseLong(s.getNumber())));

You can check the output for the following code below:

Before sorting
SearchResultObject{number='100'}
SearchResultObject{number='2'}
SearchResultObject{number='10'}
After sorting
SearchResultObject{number='2'}
SearchResultObject{number='10'}
SearchResultObject{number='100'}

The above output is based on the assumption the SearchResultObject contains a number as the field.

If you can modify SearchResultObject add a method to it converting the String to BigInteger and use it in your Comparator

public SearchResultObject {
    ...
    public BigInteger getNumberAsBigInteger() {
        return new BigInteger(this.number);
    }
    ...
}

And the invocation is

returnedValues.stream()
              .sorted(
                  Comparator.comparing(
                      SearchResultObject::getNumberAsBigInteger
                  )
              )
              .collect(Collectors.toList());

If you can't modify the SearchResultObject class, then you'll have to customize your Comparator a bit, but nothing too complicated

returnedValues.stream()
              .sorted(
                  Comparator.comparing(
                      sro -> new BigInteger(sro.getNumber())
                  )
              )
              .collect(toList());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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