[英]How can I sort a list of clothing sizes (e.g. 4XL, S, 2XL)?
I need your help follow query.我需要您的帮助来跟踪查询。 Given the following List:
鉴于以下列表:
["2XL", "3XL", "4XL", "5XL", "6XL", "L", "M", "S", "XL"]
How do I sort it so that it is in this order?我如何对其进行排序以使其按此顺序排列?
["S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL", "6XL"] [“S”、“M”、“L”、“XL”、“2XL”、“3XL”、“4XL”、“5XL”、“6XL”]
Note that every size is not always present.请注意,并非所有尺寸都存在。
Build a comparator which does a lookup on your desired order:构建一个比较器,它会根据您想要的顺序进行查找:
Comparator<String> sizeOrder = Comparator.comparingInt(desiredOrder::indexOf);
where哪里
desiredOrder = Arrays.asList("S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL", "6XL");
Then:然后:
yourList.sort(sizeOrder);
If you want, you can build a Map<String, Integer>
for the lookup:如果需要,您可以为查找构建一个
Map<String, Integer>
:
Map<String, Integer> lookup =
IntStream.range(0, desiredOrder.length())
.boxed()
.collect(Collectors.toMap(desiredOrder::get, i -> i));
And then do:然后做:
Comparator<String> sizeOrder = Comparator.comparing(lookup::get);
I'm not convinced that this will be any more performant than using List.indexOf
, because the desiredOrder
list is so small.我不相信这会比使用
List.indexOf
更List.indexOf
,因为desiredOrder
列表太小了。
As with everything performance-related: use the one which you find most readable;与所有与性能相关的内容一样:使用您认为最易读的; profile if you think this is a performance bottleneck, and only then try alternatives.
profile 如果您认为这是一个性能瓶颈,那么只有尝试替代方案。
A general approach would focus on the pattern behind the size strings rather than just accommodating the sample input.一般方法将关注大小字符串背后的模式,而不仅仅是容纳样本输入。 You have a fundamental direction denoted by
S
, M
, or L
and optional modifiers before it (unless M
) altering the magnitude.您有一个由
S
、 M
或L
表示的基本方向和可选的修饰符(除非M
)改变幅度。
static Pattern SIZE_PATTERN=Pattern.compile("((\\d+)?X)?[LS]|M", Pattern.CASE_INSENSITIVE);
static int numerical(String size) {
Matcher m = SIZE_PATTERN.matcher(size);
if(!m.matches()) throw new IllegalArgumentException(size);
char c = size.charAt(m.end()-1);
int n = c == 'S'? -1: c == 'L'? 1: 0;
if(m.start(1)>=0) n *= 2;
if(m.start(2)>=0) n *= Integer.parseInt(m.group(2));
return n;
}
Then, you can sort a list of sizes like然后,您可以对尺寸列表进行排序,例如
List<String> sizes = Arrays.asList("2XL", "5XL", "M", "S", "6XL", "XS", "3XS", "L", "XL");
sizes.sort(Comparator.comparing(Q48298432::numerical));
System.out.print(sizes.toString());
where Q48298432
should be replaced with the name of the class containing the numerical
method.其中
Q48298432
应替换为包含numerical
方法的类的名称。
An alternative using the probably more efficient and certainly clearer enum
route.使用可能更有效且当然更清晰的
enum
路线的替代方法。
// Sizes in sort order.
enum Size {
SMALL("S"),
MEDIUM("M"),
LARGE("L"),
EXTRA_LARGE("XL"),
EXTRA2_LARGE("2XL"),
EXTRA3_LARGE("3XL"),
EXTRA4_LARGE("4XL"),
EXTRA5_LARGE("5XL"),
EXTRA6_LARGE("6XL");
private final String indicator;
Size(String indicator) {
this.indicator = indicator;
}
static final Map<String,Size> lookup = Arrays.asList(values()).stream()
.collect(Collectors.toMap(
// Key is the indicator.
s -> s.indicator,
// Value is the size.
s-> s));
public static Size lookup(String s) {
return lookup.get(s.toUpperCase());
}
// Could be improved to handle failed lookups.
public static final Comparator<String> sizeOrder = (o1, o2) -> lookup(o1).ordinal() - lookup(o2).ordinal();
}
public void test(String[] args) {
List<String> test = Arrays.asList("S","6XL", "L");
Collections.sort(test, Size.sizeOrder);
System.out.println(test);
}
Another way could be this:另一种方式可能是这样的:
List<String> desiredOrder = Arrays.asList("S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL", "6XL");
String [] array = new String[desiredOrder.size()];
list.forEach(s->{
if (desiredOrder.indexOf(s) != -1)
array[desiredOrder.indexOf(s)] = s;
});
List<String> set= Stream.of(array).filter(Objects::nonNull).collect(Collectors.toList());
Or或者
Set<Integer> integers = new HashSet<>();
list.forEach(s -> {
if (desiredOrder.indexOf(s) != -1) {
integers.add(desiredOrder.indexOf(s));
}
});
List<String> sortedItems = integers.stream()
.sorted()
.map(i->desiredOrder.get(i))
.collect(Collectors.toList());
This is a basic algorithm to complete the size sorting.这是完成大小排序的基本算法。 the basic idea of this algorithm is break each parts (
number
, modifier
, unit
) of size into the corresponding regions ( [0, 1000)
, [1000, 1000_000)
, [1000_000, reset]
), and then use dir
to decide the direction of the modifier
.该算法的基本思想是将大小的每个部分(
number
、 modifier
、 unit
)分解为相应的区域( [0, 1000)
、 [1000, 1000_000)
、 [1000_000, reset]
),然后使用dir
来决定modifier
方向。 for example:例如:
class Size {
public static int sizeToInt(String size) {
int n = size.length(), unit = size.charAt(n - 1), dir = unit == 'S' ? 1 : -1;
//use a separate method to parse the number & extra modifier if needed
int i = 0;
int number = n > 1&&Character.isDigit(size.charAt(i)) ? size.charAt(i++) : '1';
int modifier = i + 1 < n ? size.charAt(i) : 0;
return -1 * (unit * 1000_000 + dir * (modifier * 1000 + number));
}
}
The solution above is just for the simple case as yours, for the complex case you need to parse number
& modifier
and decide how to partition the region
s.上面的解决方案仅适用于您的简单情况,对于复杂情况,您需要解析
number
& modifier
并决定如何对region
进行分区。 Then you can sort sizes by Comparator
as following code:然后您可以按以下代码按
Comparator
对大小进行排序:
Comparator<String> sizeComparator = Comparator.comparingInt(Size::sizeToInt);
List<String> sizes = Arrays.asList(
"3XL", "2XL", "XL",
"5L", "2L", "L",
"5M", "2M", "M",
"S", "2S", "3S",
"XS", "2XS", "3XS"
);
sizes.sort(sizeComparator);
System.out.println(sizes);
// ^--- [
// "3XS", "2XS", "XS",
// "3S", "2S", "S",
// "M", "2M", "5M",
// "L", "2L", "5L",
// "XL", "2XL", "3XL"
// ]
Create an Enum class with all the possible sizes and add to it the getEnum
method to support the sizes that start by number:创建一个包含所有可能大小的 Enum 类,并向其中添加
getEnum
方法以支持以数字开头的大小:
public enum SizeEnum
{
S("S"), M("M"), L("L"), XL("XL"), TWO_XL("2XL"), THREE_XL("3XL"), FOUR_XL("4XL"), FIVE_XL("5XL"), SIX_XL("6XL");
private String value;
SizeEnum(String value){
this.value = value;
}
public String getValue() {
return value;
}
public static SizeEnum getEnum(String value) {
return Arrays.stream(values())
.filter(v -> v.getValue().equalsIgnoreCase(value))
.findAny()
.orElseThrow(() -> new IllegalArgumentException());
}
}
Use the SizeEnum
class in the comparator:在比较器中使用
SizeEnum
类:
List<String> sizes = Arrays.asList("2XL", "3XL", "4XL", "5XL", "6XL", "L", "M", "S", "XL");
sizes.sort(Comparator.comparing(v -> SizeEnum.getEnum(v.toUpperCase())));
sizes.stream().forEach(l -> System.out.println(l));
public static void SortSizes(String [] sizes, String [] sortedRadixArr) throws Exception{
//creating an int array with same length as sortedRadixArr
//Here each index of intRadix array is mapped to the index of sortedRadixArr
//Eg: intRadix = [0,0,0,0,0] ----> ["S","M","L","XL","2XL"]
int [] intRadix = new int[sortedRadixArr.length];
for(int i = 0; i < sizes.length; i++){
boolean matchFlag = false;
for(int j=0; j< sortedRadixArr.length; j++){
if(sizes[i] == sortedRadixArr[j]){
//Whenever the String is matched with the String of sortedRadixArr array,
//increment the value of intRadix array at the equivalent index of sortedRadixArr.
//This helps us to count number same strings(sizes). like two or more "S".
//We can't do that with sortedRadixArr as it is a String array.
intRadix[j]++;
matchFlag = true;
break;
}
}
if(!matchFlag){
throw new Exception("Invalid size found!");
}
}
int count = 0;
for(int k = 0; k < intRadix.length; k++){
//Loop thru intRadix array. It contains count of respective sizes(Strings) at each index.
//We will re-write sizes array in sorted order with help of intRadix as below.
while(intRadix[k] > 0){
sizes[count++] = sortedRadixArr[k];
intRadix[k]--;
}
}
}
} }
Here, sortedRadixArr
is the radix array ie values with all possible values:这里,
sortedRadixArr
是基数数组,即具有所有可能值的值:
["S", "M", "L", "XL", "2XL", "3XL", "4XL", "5XL", "6XL"]
sizes
is the array that you wanna sort: sizes
是您要排序的数组:
["2XL", "3XL", "4XL", "5XL", "6XL", "L", "M", "S", "XL"]
It accepts duplicate values.它接受重复值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.