[英]Is there any way to sort an arraylist which have 2 classes by stream or whatever?
I know this question might be ridiculous complicated but this is something I must achieve... Assume I have a list of 'entities':我知道这个问题可能是荒谬的复杂,但这是我必须实现的目标......假设我有一个“实体”列表:
//they are all in the PlayGround class
public static interface Entity{
void turn(PlayGround g);
int x();
int y();
int radius();
}
public ArrayList<Entity> entities(){return entities;}
ArrayList<Entity> entities=new ArrayList<>();
Then I have two subclasses rock and miner extends from Entity:然后我有两个子类岩石和矿工从实体扩展:
//Record is a new feature in Java14 which similar to create a new class with fields
@SuppressWarnings("preview")
record Rock(int x,int y, int radius) implements Entity, Comparable<Rock>{
...
public int compareTo(Rock o) {return Integer.compare(radius,o.radius);}
public int getRadius() {return radius;};
}
class Miner implements Entity{
int x=100;int y=100;
public int x(){return x;}
public int y(){return y;}
public int radius(){return 15;}
...
}
In that case, we can add elements like this:在这种情况下,我们可以添加这样的元素:
var mg=new PlayGround();
mg.entities().add(new Rock(200,200,50));
mg.entities().add(new Rock(250,100,40));
mg.entities().add(new Rock(200,350,80));
mg.entities().add(new Miner());
However, I want to sort the Rock class in the Arraylist by the number of radius, in the example, the ArrayList will from[Rock(50), Rock(40), Rock(80), Miner()] to [Rock(80), Rock(50), Rock(40), Miner()].但是,我想按半径对Arraylist中的Rock类进行排序,在示例中,ArrayList将从[Rock(50), Rock(40), Rock(80), Miner()] 到 [Rock( 80),岩石(50),岩石(40),矿工()]。
From the former query I tried:从我尝试过的前一个查询中:
var es = mg.entities();
@SuppressWarnings("unchecked")
ArrayList<Entity> ess = es.stream()
.filter(Rock.class::isInstance)
.map(Rock.class::cast)
.sorted(Comparator.comparingInt(Rock::getRadius))
.collect(Collectors
.toCollection(ArrayList::new));
But it only compares the rock class and filter Miner out in the result.但它只比较摇滚类并在结果中过滤掉 Miner。 Is there any way to achieve this?
有没有办法实现这一目标? Thanks!
谢谢!
There's no need to involve stream API.无需涉及流 API。
Your description of the problem is unclear.您对问题的描述不清楚。 As is supposed to happen with unclear tasks, it is not possible to write an unclear task in code, as computers require very specific instructions.
正如不明确的任务应该发生的那样,不可能在代码中编写不明确的任务,因为计算机需要非常具体的指令。
The part that is unclear is: How do miners relate in this sorting algorithm of yours?不清楚的部分是:矿工在你的这个排序算法中是如何关联的?
Given [rock5,rock2,miner1,rock10]
, there are many answers possible:鉴于
[rock5,rock2,miner1,rock10]
,有很多可能的答案:
[rock2,rock5,rock10,miner1]
[rock2,rock5,rock10,miner1]
[miner1,rock2,rock5,rock10]
.[miner1,rock2,rock5,rock10]
。 They're really all relatively tricky;它们确实都比较棘手; you can't do this by chaining a few
Comparator::comparingInt
and friends together.你不能通过将几个
Comparator::comparingInt
和朋友链接在一起来做到这一点。 You can write your own comparator that does the job, but note that technically comparators should remain consistent.您可以编写自己的比较器来完成这项工作,但请注意,从技术上讲,比较器应保持一致。 If a comparator says that 'a is below b', then if later asked about 'b and a', it MUST answer that 'b is above a', or things break in bizarre ways.
如果比较器说“a 低于 b”,那么如果稍后询问“b 和 a”,它必须回答“b 高于 a”,否则事情会以奇怪的方式破裂。 That complicates matters, there isn't really a 'eh, whatever, don't try to order these things' option.
这让事情变得复杂,真的没有“呃,无论如何,不要试图订购这些东西”的选项。 For sorting arraylists you can return 'I consider these at the same level', but note that
TreeMap
and TreeSet
can't do that (any 2 things at the same level are considered the same key).对于排序数组列表,您可以返回“我认为它们处于同一级别”,但请注意
TreeMap
和TreeSet
不能这样做(同一级别的任何 2 件事都被认为是相同的键)。
That consistency is really a problem here.这种一致性在这里确实是一个问题。 If you say that all miners are at the same level of all rocks, you can't do that.
如果你说所有矿工都在所有岩石的同一级别,你就不能那样做。 If rock1 is below rock2, but rock1 is at the same level as miner1, and miner1 is at the same level as miner2, boom, inconsistent.
如果rock1低于rock2,但是rock1和miner1在同一水平,miner1和miner2在同一水平,boom,不一致。
So, your comparator has to get pretty complicated:因此,您的比较器必须变得非常复杂:
es.sort((a, b) -> {
// miners are at the same level as each other.
if (a instanceof Miner && b instanceof Miner) return 0;
// miners are below all rocks
if (a instanceof Miner) return -1;
if (b instanceof Miner) return +1;
// they're both rocks.
return Integer.compare(((Rock) a).getRadius(), ((Rock b).getRadius());
});
that one would be consistent, and sorts all miners to the front.那将是一致的,并将所有矿工排序到前面。
If you want to sort 'around' the miners, I don't think list.sort (or Collections.sort) is capable of that, so fire up your favorite search engine and recreate TIMsort or quicksort or whatnot.如果您想对矿工进行“周围”排序,我认为 list.sort(或 Collections.sort)无法做到这一点,因此请启动您最喜欢的搜索引擎并重新创建 TIMsort 或 quicksort 或诸如此类的东西。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.