我用来存储重复对象的列表/数组作为映射,其中键是对象本身,值是它的多重性。
说['d', 'a', 'd', 'd', 'y']
-> {d=3, a=1, y=1}
(顺序保留,FWIW)
我这样做既是为了节省字节,也是因为操作这个计数映射使我的工作更容易
有时我确实需要返回到列表/数组形式,
说{d=3, a=1, y=1}
—> ['d', 'd', 'd', 'a', 'y']
显然,原始顺序不能重新创建,该信息丢失了,但这是不相关的,因为我认为等效的两个列表/数组如果它们具有相同的大小并共享完全相同的元素(包括相对多重性)
从Map到List,我写了以下方法:
<T> ArrayList<T> counted2Lst(final LinkedHashMap<T, Integer> map){
final ArrayList<T> grp=new ArrayList<T>(map.size()); // larger most of the times
for (final Entry<T, Integer> entry : map.entrySet()) {
final T obj=entry.getKey();
for(int i=entry.getValue(); i>0; i--){
grp.add(obj);
}
}
return grp;
}
完成了预期的工作:从Map
构建一个数组列表当我决定做同样的事情时,我遇到了问题,但是得到一个T[](不是一个对象[])而不是一个数组列表
这是我的第一次尝试:
<T> T[] counted2Arry(final Map<T, Integer> map){
final ArrayList<T> tmpLst=counted2Lst(map); // method defined above
@SuppressWarnings("unchecked")
T[] arryT=(T[]) java.lang.reflect.Array.newInstance(tmpLst.get(0).getClass(), tmpLst.size());
return tmpLst.toArray(arryT);
}
据我所知,由于类型擦除,没有办法在运行时获得集合/映射的参数化类型,因此,要创建一个T的数组,我必须首先获得存储在tmpLst中的第一个对象的Class(授予类型为T)然后通过java.lang.reflect.Array.newInstance()生成一个T的数组
问题是,如果输入映射是空的(这是完全合理和合法的情况),那么就没有对象可以从中检测t的实际类。
换句话说,在Java中我怎么说呢?
if(map.size()==0) { // or (tmpLst.size()==0)
// return a zero-sized T[0] (as opposed to a zero-sized Object[])
}
您应该真正签出Guava的Multiset
(或SortedMultiset
)。它基本上完全完成了你在代码中所做的事情,而且是在一个经过生产验证的库中。
下面是一个例子:
char[] chars = new char[]{'d', 'a', 'd', 'd', 'y'};
// unsorted version
ImmutableMultiset.Builder<Character> builder =
ImmutableMultiset.builder();
for (char c : chars) builder.add(c);
ImmutableMultiset<Character> mset = builder.build();
System.out.println(new ArrayList<>(mset));
// sorted version
ImmutableSortedMultiset.Builder<Character> sortedBuilder =
ImmutableSortedMultiset.naturalOrder();
for (char c : chars) sortedBuilder.add(c);
ImmutableSortedMultiset<Character> sortedMset = sortedBuilder.build();
System.out.println(new ArrayList<>(sortedMset));
// how to get an array
Object[] array = mset.toArray();
System.out.println(Arrays.toString(array));
EDIT:我不建议自己编写方法,但这是ArrayList.toArray
在Oracle JDK 7中的实现方式:
public <T> T[] toArray(T[] a) {
if (a.length < size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length > size)
a[size] = null;
return a;
}
EDIT 2:添加上面的Guava代码示例。我意识到,没有办法做OP试图做的事情,除非映射至少有一个键,或者你传递一个(可能是空的)T[]
,并使用上面描述的整个JDK使用的方法,或者至少有Class<T>
可用(见这个SO):
public <T> T[] toArray(Class<T> type) {
int size = // define size of returned array
T[] ret = (T[]) Array.newInstance(type, size)
// fill the array
return ret;
}
您可以获取条目集的大小。
if (map.entrySet().size() == 0) { /* do things */ }