假设我们有一堆Car对象。
每辆车都有一些与众不同的特性,例如:制造商,型号,年份等(这些可用于创建不同的hashCodes)。
每辆车都有一个PurchaseOffer对象列表(PurchaseOffer对象包含定价\零售商信息)。
我们收到来自几个不同来源的汽车列表,每辆汽车都有一个PurchaseOffer。 事实是,这些列表可能会重叠 - Car可以出现在多个列表中。
我们希望将列表汇总到一个汽车集合中,其中每辆汽车都拥有所有遇到的PurchaseOffers。
我的问题是在此聚合过程中选择要收集的内容:
感觉很自然地使用java.util.HashSet来保存我们的汽车,这样当经过不同的汽车列表时,我们可以检查汽车是否已经存在于已摊销的O(1)中, 但是 - 你无法从一个Set中检索一个元素(在我们的例子中 - 当我们遇到一个已经存在于Set中的Car时 - 我们本来希望根据它的标识hashCode从Set中检索那个Car并向其添加PurchaseOffers)
我可以使用HashMap,其中每个Car的hashCode映射到实际的Car对象,但它可能不是学校书籍解决方案,因为它不安全 - 我必须确保自己每个hashCode映射到一个Car hashCode - 可能存在不一致。 当然,可以制作一个保证这种一致性的指定数据结构 - 不应该已经存在吗?
有人能建议我追求的数据结构,还是指出设计错误? 感谢。
答案 0 :(得分:6)
由于这是多对多关系,因此您需要一个双向多地图。 Car是第一个的关键,List of PurchaseOrder作为值。 PurchaseOrder是第二个的关键,以汽车列表作为值。
底层实现是两个HashMaps。
在其上放置API以获得所需的行为。或者看看Google Collections是否可以为您提供帮助。它是BiMap和两个MultiMaps的组合。
答案 1 :(得分:5)
我认为你确实需要(至少)HashMap<Car, List<PurchaseOffer>>
......正如@Andreas_D所建议的
您的反对意见认为每个Car
已经有List<PurchaseOffer>
。 HashMap
中的列表是聚合列表,其中包含来自代表同一实体汽车的所有PurchaseOffer
个对象的所有 Car
个对象。
创建新列表的目的是避免更改原始Car
对象上的原始列表。 (如果这不是问题,那么您可以从代表物理汽车的集合中选择一个Car
实例,并将其他PurchaseOffer
个对象合并到该列表中。)
我不完全确定为什么@duffymo建议在它们之间使用双向地图,但我认为这是因为来自不同来源的不同Car
对象可能对同一辆实体车具有互补(或相互矛盾)的信息。通过保留所有实例,您可以避免丢弃信息。 (再次,如果您乐意放弃变异和/或丢弃信息,您可以尝试将每辆汽车的信息合并到一个Car
对象中。
如果你真的不关心保存信息并且准备好合并的东西,那么以下方法可能会有效:
HashMap<Car, Car> map = new HashMap<Car, Car>(...);
for (Car car : carsToBeAggregated) {
Car master = nap.get(car);
if (master == null) {
map.put(car, car);
} else {
master.offers.addAll(car.offers);
// optionally, merge other Car information from car to master
}
}
您不应该尝试使用Car.hashCode()
作为任何关键。 Hashcode值不是唯一标识符:两种不同的汽车最终会有相同的哈希码值。如果您尝试使用它们就好像它们是唯一标识符一样,您将遇到麻烦......
答案 2 :(得分:3)
基本数据结构应为HashMap<Car, List<PurchaseOffer>>
。这允许存储和接收所选汽车的所有报价。
现在你可能必须为Car.equals()
找到一个合适的实现,以确保来自不同来源的“汽车”真的是一样的。将equals()
基于真实世界汽车的唯一标识符(VIN)怎么样?
答案 3 :(得分:1)
我更喜欢使用HashMap<Car, List<PurchaseOffer>>
,如前所述(Andreas,Stephen),主要是如果Car对象不持有PurchaseOffers列表。
否则,如果每辆车都有唯一的ID,我会考虑使用HashMap<Car, Car>
或更好的IMO HashMap<ID, Car>
。
它可以不简单地将Car的hashCode映射到Car,如问题中所述,因为不同的Cars可以具有相同的hashCode!
(无论如何,我会创建一个自己的类来存储和管理Cars。这将包含HashMap,或者哪个 - 所以很容易更改实现而无需更改其界面)
答案 4 :(得分:0)
创建扩展哈希的自定义类
设置,
覆盖方法包含(对象o)
检查os哈希码是否相同并返回结果,并将对象添加到集合中并且仅当它不包含该对象时
答案 5 :(得分:0)
定义新的自定义聚合类怎么样?定义哈希码,使得汽车的id充当密钥并相应地覆盖equals()。定义接受原车的自定义方法,并在列表上执行联合操作。最后将自定义对象存储在HashSet中,以实现持续的时间查找。
在纯粹的术语中,聚合是超出单个对象范围的行为。访客模式试图解决类似的问题。
或者如果你有一个sql数据存储区,使用group by的简单选择就可以了。
答案 6 :(得分:0)
//alt. 1
List<Offer> offers;
List<Car> cars;
Map<Car, List<Offer>> mapCarToOffers;
Map<Offer, List<Car>> mapOfferToCars;
public void List<Offer> getOffersForCar(Car aCar);
public void List<Car> getCarsForOffer(Offer anOffer);
备选方案1 会使用hashCode()
和Car
Offer
//alt. 2
List<Offer> offers;
List<Car> cars;
Map<Integer, List<Offer>> mapCarIdToOffers;
Map<Integer, List<Car>> mapOfferIdToCars;
public void List<Offer> getOffersForCarId(int aCarId);
public void List<Car> getCarsForOfferId(int anOfferId);
备选方案2 会使用hashCode()
的{{1}}。这可以减轻您对“安全”的担忧,因为Integer
对象的哈希码不应该在值唯一的位置重叠。这会产生额外的开销,即必须为每个Integer
和Car
对象维护唯一ID,但是,我猜您可能已经拥有了符合您业务要求的ID。
请注意,您可以选择使用其他类作为ID的Offer
替代(例如int
)。
对于这两种选择,请使用String
或List
实施ArrayList
- 根据其他要求(例如插入频率/删除与查找。使用LinkedList
实施Map
- 请参阅上面有关如何使用哈希码的注释。
作为旁注,在我们的软件中,我们使用上述两者来表示类似类型的多对多数据。与您的用例非常相似。 两种选择都很有效。
答案 7 :(得分:0)
Welp,是的,
HashMap<Car, List<PurchaseOffer>>
如果不是因为这个事实将是完美的 每个Car
都包含List<PurchaseOffer>
作为属性。可以说组成了一个Car
对象 两部分:识别部分(假设每辆车确实有一个独特的VIN),以及清单PurchaseOffer
秒。
在这种情况下,将Car类拆分为两个类 - 具有标识属性的CarType类,然后是列表部分(可能由Car
一起使用)。然后使用Map<CarType, Lost<PurchaseOffer>
作为数据结构(或MultiMap<CarType, PurchaseOffer>
)。
答案 8 :(得分:-1)
为什么不为此使用对象数据库?您可以存储您想要的任何对象图,并且您将获得一个搜索API,您可以使用它来执行您想要的任何关系/检索机制。一个简单的集合可以工作,但听起来你想要一个比集合更复杂的关系。查看db4o(http://db4o.com) - 它对于这类事情非常强大。