仅在 Java 中按键排序 Multimap
我想要一个仅根据键排序的 cgccMultimap
。不应对值进行排序。我尝试使用 guava 的 TreeMultimap 构建一些东西,但我无法使用它,因为值类型没有实现 Comparable。
public class MyObject /* doesn't implement Comparable */ {
private String name;
private int score;
// Getters/setters are implemented
public static Function<MyObject,Integer> myObjectToScore {
@Override public Integer apply (MyObject o) { return o.score; }
}
public static Multimap<Integer,MyObject> indexOnScore(Iterable<MyObject> i) {
Multimap<Integer,MyObject> m = Multimaps.index(i, myObjectToScore());
// Do the sort of the keys.
return m;
}
}
我考虑过获取键的 SortedSet
,然后迭代排序集中的每个键以获取各种值,但我希望使用 Guava 中现有的(尚未发现的)功能而不是使用这种黑客。
注意:我不会让 MyObject
实现 Comparable
因为它对我的实际对象没有意义。
输入/输出示例:
Set<MyObject> s = Sets.newHashSet(
new MyObject("a", 2),
new MyObject("b", 3),
new MyObject("c", 1),
new MyObject("d", 3),
new MyObject("e", 1)
); // Assuming constructor MyObject(String name, int score)
for (Map.Entry<Integer, MyObject> e: MyObject.indexedOnScore(s).entries()) {
System.out.printf("%d -> %s%n", e.getKey(), e.getValue().getName());
}
打印:
1 -> c // or switched with line below
1 -> e
2 -> a
3 -> b // or switched with line below
3 -> d
I would like to have a c.g.c.c.Multimap
that is sorted based on keys only. The values shouldn't be sorted. I've tried to build something with guava's TreeMultimap
, but I can't use it because the value type doesn't implement Comparable
.
public class MyObject /* doesn't implement Comparable */ {
private String name;
private int score;
// Getters/setters are implemented
public static Function<MyObject,Integer> myObjectToScore {
@Override public Integer apply (MyObject o) { return o.score; }
}
public static Multimap<Integer,MyObject> indexOnScore(Iterable<MyObject> i) {
Multimap<Integer,MyObject> m = Multimaps.index(i, myObjectToScore());
// Do the sort of the keys.
return m;
}
}
I've thought about getting a SortedSet
of the keys, then iterating over each of these keys in the sorted set to fetch the various values, but I was hoping using an existing (yet undiscovered) feature in Guava rather than using this kind of hack.
Note: I won't make MyObject
implement Comparable
because it makes no sense with my actual object.
Example of input/output:
Set<MyObject> s = Sets.newHashSet(
new MyObject("a", 2),
new MyObject("b", 3),
new MyObject("c", 1),
new MyObject("d", 3),
new MyObject("e", 1)
); // Assuming constructor MyObject(String name, int score)
for (Map.Entry<Integer, MyObject> e: MyObject.indexedOnScore(s).entries()) {
System.out.printf("%d -> %s%n", e.getKey(), e.getValue().getName());
}
Prints:
1 -> c // or switched with line below
1 -> e
2 -> a
3 -> b // or switched with line below
3 -> d
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
对我来说总是有效的最佳解决方案是使用 Multimap &树多重映射。即使您有多个重复的键,这也会按键的升序对结果进行排序。解决方案如下:
Best solution which always works for me is to use Multimap & TreeMultiMap. this will order results in ascending order on keys even if you have multiple duplicate keys. Solution below:
Multimaps.index
返回一个ImmutableListMultimap
,因此在创建它后您将无法对其进行排序。但是,您可以首先创建Iterable
的排序副本,并将其提供给Multimap.index
...ImmutableListMultimap
保留内容按照给他们的顺序。另一种选择可能是创建一个
TreeMultimap
并使用Ordering.graduatery()
作为值的Comparator
。Multimaps.index
returns anImmutableListMultimap
, so you wouldn't be able to sort it after creating it. You could, however, first create a sorted copy of yourIterable<MyObject>
and feed that toMultimap.index
...ImmutableListMultimap
keeps things in the same order it was given them.Another option might be to create a
TreeMultimap
and useOrdering.arbitrary()
as theComparator
for the values.MultimapBuilder
是在 Guava 16 中引入的:
这使您的键按其自然顺序排序(
MultimapBuilder::treeKeys
也被重载以接受自定义比较器),以及与每个键关联的值维护在LinkedList
中(ArrayList
和HashSet
是其他选项)。MultimapBuilder
was introduced in Guava 16:That keeps your keys sorted by their natural order (
MultimapBuilder::treeKeys
is also overloaded to accept a custom comparator), and the values associated with each key are maintained in aLinkedList
(ArrayList
andHashSet
are among the other options).尽管OP的具体情况似乎已经使用不可变的多重映射构建函数得到了回答,但我需要他所要求的可变版本。如果它对任何人有帮助,这是我最终创建的通用方法:
Though the OP's specific situation seems to have been answered using immutable multimap building functions, I needed a mutable version of what he was asking for. In case it helps anyone, here's the generic method I ended up creating:
调用 Multimaps.newMultimap,它使您可以灵活地创建例如由 TreeMap 支持的 Multimap,其值为 ArrayList。
Call Multimaps.newMultimap, which gives you the flexibility to create, for example, a Multimap backed by TreeMap whose values are ArrayLists.
我想指出的是,建议的替代解决方案,即“创建 TreeMultimap 并使用 Ordering. Arbitration() 作为值的比较器”,仅在 MyObject 不覆盖 equals 的情况下才有效() 或 hashcode()。 Ordering.任意()与 equals 不一致,而是使用对象标识,这使得将其与 TreeSet 结合使用不是一个好主意。
I'd like to point out that the alternative proposed solution, namely "to create a TreeMultimap and use Ordering.arbitrary() as the Comparator for the values", only works if MyObject doesn't override equals() or hashcode(). Ordering.arbitrary() is inconsistent with equals and uses object identity instead, which makes it not a good idea to use it in conjunction with a TreeSet.
怎么样:
不过,在这种情况下,创建两个单独的 Multimap 会产生开销。
How about this:
There would be the overhead of creating two separate
Multimap
s in this case, though.您可以使用 TreeMultimap 来完成此操作 如果您使用比较器。
创建一个 比较器 用于键类型和值类型(
MyObject
?)。然后使用 create(Comparator keyComparator, Comparator valueComparator) 来制作地图。使用 Comparator 相对于实现 Comparable 的好处是,您可以使 Comparator 特定于您想要的地图情况,并且它通常不会影响您的对象。只要你的比较器与 equals 一致,它就可以做你想做的任何事情。
You can do it with TreeMultimap if you use Comparators.
Create a Comparator for the key type and the value type (
MyObject
?). Then use create(Comparator keyComparator, Comparator valueComparator) to make the map.The benefit of using a Comparator over implementing Comparable is that you can make the Comparator specific to the situation that you want with the map and it doesn't effect your object in general. As long as your Comparator is consistent with equals it can do whatever you want.