从Collection/Map中获取参数化数组



我用来存储重复对象的列表/数组作为映射,其中键是对象本身,值是它的多重性。

['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 */ }

相关内容

  • 没有找到相关文章

最新更新