我能以某种方式访问列表中对象的索引吗?
myList.stream().sorted((o1, o2) -> 0).collect(Collectors.toList())
e.g:
我希望首先显示奇数索引,最后显示索引。
答案 0 :(得分:5)
我不认为基于索引的重新排序操作是实际的排序操作。例如,没有人会考虑实施像Collections.reverse(List)
这样的操作作为排序操作。
将奇数位置的元素移动到前面的有效方法是
public static <T> void oddFirst(List<T> list) {
final int size = list.size();
for(int index1=0, index2=list.size()/2|1; index2<size; index1+=2, index2+=2)
Collections.swap(list, index1, index2);
}
或者,您可以流式传输this answer中的索引,以生成新的List
。
答案 1 :(得分:2)
过滤器可能有所帮助:
List<Integer> listEvenIndicesMembers = IntStream.range(0, list.size()).filter(n -> n % 2 == 0).mapToObj(list::get)
.collect(Collectors.toList());
List<Integer> listOddIndicesMembers = IntStream.range(0, list.size()).filter(n -> n % 2 != 0).mapToObj(list::get)
.collect(Collectors.toList());
System.out.println(listEvenIndicesMembers);
System.out.println(listOddIndicesMembers);
问题是现在你有2个列表,一个接一个地追加将产生你想要的相同...我仍在检查文档,也许我找到更优雅/优化的东西。[1,3,5,7,9,11]
[2,4,6,8,10]
感谢@Holger提出的建议:
你可以连接流:
List<Integer> listOptimal = IntStream
.concat(IntStream.range(0, list.size()).filter(n -> n % 2 == 0),
IntStream.range(0, list.size()).filter(n -> n % 2 != 0))
.mapToObj(list::get).collect(Collectors.toList());
System.out.println(listOptimal);
答案 2 :(得分:1)
我认为ΦXocę 웃 Пepeúpa ツ的解决方案对你来说应该没问题,这里只是另一种选择(记住,它只是一种替代方法,为了学习,这个解决方案不应该用于'现实生活',它只是为了显示可能性):
public static void main(String arg[]) {
List<String> list = Arrays.asList("A", "B", "C", "D", "E", "F", "G", "H");
List<String> listCopy = new ArrayList<>(list);
list.sort((o1, o2) -> Integer.compare(listCopy.indexOf(o2) % 2, listCopy.indexOf(o1) % 2));
System.out.println(list);
}
输出为:[B, D, F, H, A, C, E, G]
答案 3 :(得分:1)
接受的答案有效,但这也有效(只要列表中没有重复项):
// a list to test with
List<String> list = Arrays.asList("abcdefghijklmnopqrstuvwxyz".split(""));
List<String> list2 = list.stream()
.sorted(Comparator.comparing(x -> list.indexOf(x) % 2).thenComparing(x -> list.indexOf(x)))
.collect(Collectors.toList());
list2.forEach(System.out::print);
首先打印奇数索引,然后打印偶数索引
acegikmoqsuwybdfhjlnprtvxz
只是为了说明霍尔格在评论中提出的观点。
答案 4 :(得分:1)
您可以使用装饰器模式存储对象以及用于排序的额外信息。例如。如果你有一个你想要排序的字符串列表(添加getter):
class StringWithIndex {
String text;
int index;
int evenIndex;
StringWithIndex(String text, int index) {
this.text = text;
this.index = index;
this.evenIndex = index % 2 == 0 ? 1 : -1;
}
}
然后你可以对这些对象进行排序而不是字符串:
List<String> strings = Arrays.asList("a", "b", "c", "d");
List<String> sorted = IntStream.range(0, strings.size())
.mapToObj(i -> new StringWithIndex(strings.get(i), i))
.sorted(comparingInt(StringWithIndex::getEvenIndex).thenComparingInt(StringWithIndex::getIndex))
.map(StringWithIndex::getText)
.collect(Collectors.toList());
这会增加一些开销来创建临时对象并需要另一个类。但随着排序规则变得更加复杂,它可以证明非常有用。
答案 5 :(得分:0)
如果您只想根据索引移动List
值,那么请参阅我的其他答案。
但是,您问题的原始措辞表明您希望将sort()
或sorted()
与比较器一起使用,该比较器会考虑现有位置以及该值的其他方面。
如果你刚刚使用Collections.sort()
,这也很困难,因为那里使用的Comparator
也无法访问索引。
您可以将Stream<T>
映射到Stream<Entry<Integer,T>>
,并在完成后将其映射回Stream<T>
:
(这是AbstractMap.SimpleEntry
- 因为它存在于标准库中 - 您也可以编写自己的Pair
或使用第三方中的一个 - 请参阅A Java collection of value pairs? (tuples?))< / p>
mystream.map(addIndex()).sorted(compareEntry()).map(stripIndex()) ...
private <T> Function<T,Entry<Integer,T>> addIndex() {
final int[] index = new int[] { 0 };
return o -> new SimpleEntry(index[0]++, o);
}
private Comparator<Entry<Integer, T>> compareEntry() {
return a,b -> {
// your comparison code here -- you have access to
// getKey() and getValue() for both parameters
};
}
private <T> Function<Entry<Integer,T>, T> stripIndex() {
return e -> e.getValue();
}
请注意,addIndex()
至少是不可并行的。我想,一旦所有条目都用索引标记,那么下游就可以并行完成。
答案 6 :(得分:0)
奖励回答 - 如果您要做的就是创建一个包含奇数条目后跟偶数条目的新列表,那么使用Stream
会增加不必要的复杂性。
for(int i=0; i<inlist.size(); i+=2) {
outlist.add(inlist.get(i));
}
for(int i=1; i<inlist.size(); i+=2) {
outlist.add(inlist.get(i));
}
还有一个非常简单的算法,可以在适当的位置重新排序列表 - 您可以自己编写。想一想 - 只要知道列表长度,就可以从旧索引中获取新索引。