以不同枚举的不同值作为键的映射

时间:2021-03-23 15:13:11

标签: java dictionary enums

假设我有两个像这样的枚举:

from sklearn.decomposition import PCA
import cv2
import numpy as np

image_filepath = 'baby_yoda_image.jpg'

# Loading image from disk.
input_image = cv2.imread(image_filepath)
height = input_image.shape[0]
width = input_image.shape[1]
channels = input_image.shape[2]

# Reshaping image to perform PCA.
print('Input image shape:', input_image.shape)
#--- OUT: (533, 800, 3)

reshaped_image = np.reshape(input_image, (height, width*channels))
print('Reshaped Image:', reshaped_image.shape)
#--- OUT: (533, 2400)

# Applying PCA transformation to image. No whitening is applied to prevent further data loss.
n_components = 64
whitening = False
pca = PCA(n_components, whitening)
compressed_image = pca.fit_transform(reshaped_image)

print('PCA Compressed Image Shape:', compressed_image.shape)
#--- OUT: (533, 64)
print('Compression achieved:', np.around(np.sum(pca.explained_variance_ratio_), 2)*100, '%')
#--- OUT: 97.0 %    

# Plotting images.
approximated_image = pca.inverse_transform(compressed_image)
approximated_original_shape_image = np.reshape(approximated_image, (height, width, channels))

cv2.imshow('Input Image', input_image)
cv2.imshow('Compressed Image', approximated_original_shape_image)
cv2.waitKey()

现在,我想实现一个查找表,使用 Map 将这些枚举值与 public enum foo { FOO1, FOO2, FOO3; } public enum bar { BAR1, BAR2, BAR3; } 值相关联,并将两个枚举值作为键,这样我就可以使用 Map 实用程序轻松地对映射进行交互,但是除了使用 int 之外,我不知道如何继续,这听起来根本不安全;我正在考虑为两个枚举创建一个超类 fooBar 并使用 Map<Object, int>,但 AFAIK 枚举不能 Map<fooBar, int> 一个类,或者创建一个带有空体的接口 extend这两个枚举可以 fooBarInterface 然后使用 implement

对于解决此问题的好方法有什么想法吗?将枚举合并为一个对我来说不是一种选择。

1 个答案:

答案 0 :(得分:1)

  1. 您对通用空接口 (FooBarInterface) 的想法很好,可以解决问题。
  2. 如果您想容纳更多枚举以及可能没有实现您的接口的枚举,您还可以使用 Enum 作为映射键类型:Map<Enum<?>, Integer> lookupTable = Map.of(Foo.FOO1, 1, Foo.FOO2, 3, Foo.FOO3, 5, Bar.BAR1, 6, Bar.BAR2, 8, Bar.BAR3, 11);

在这两种情况下,根据情况,我可能仍会保留两个单独的地图,并且仅在需要时将它们合并以进行迭代。

为了进一步推进这个想法,我什至可能会考虑开发一个关于两个地图条目集联合的视图。您需要开发自己的 Iterator 实现,该实现首先迭代第一个映射的条目集,然后是第二个映射,最后表示迭代结束(hasNext() 返回 false) .

类型安全?你说你想要的东西有一个固有的“类型不安全”。和它一起生活。除了 java.util.Map 接口的基本类型问题之外,这只是一个很小的成本:它的 get 方法接受任何对象,而不仅仅是声明键类型的对象(这是由于历史原因)。< /p>

PS 在我使用的 Java 版本中,int 根本不能是 Map 的值类型或泛型类型的类型参数。它可能是后来添加的。如果没有,您将不得不使用 Integer

编辑:迭代两个地图的简洁方式

迭代两个(或更多)映射的一种方法是通过流操作:

    Map<Foo, Integer> fooLookupTable = new EnumMap<>(Map.of(Foo.FOO1, 2, Foo.FOO2, 3, Foo.FOO3, 8));
    Map<Bar, Integer> barLookupTable = new EnumMap<>(Map.of(Bar.BAR1, 4, Bar.BAR2, 6, Bar.BAR3, 11));

    Stream.of(fooLookupTable, barLookupTable)
            .flatMap(m -> m.entrySet().stream())
            .forEach(e -> System.out.format("%4s (%3s) %2d%n",
                    e.getKey(), e.getKey().getClass().getSimpleName(), e.getValue()));

输出:

<块引用>
FOO1 (Foo)  2
FOO2 (Foo)  3
FOO3 (Foo)  8
BAR1 (Bar)  4
BAR2 (Bar)  6
BAR3 (Bar) 11

编辑:迭代多个集合的迭代器代码

为了保持两个单独的查找映射并同时迭代它们,您可能需要如下代码:

    Map<Foo, Integer> fooLookupTable = new EnumMap<>(Map.of(Foo.FOO1, 2, Foo.FOO2, 3, Foo.FOO3, 8));
    Map<Bar, Integer> barLookupTable = new EnumMap<>(Map.of(Bar.BAR1, 4, Bar.BAR2, 6, Bar.BAR3, 11));
    
    IterableUnion<Entry<? extends Enum<?>, Integer>> union
            = new IterableUnion<>(fooLookupTable.entrySet(), barLookupTable.entrySet());
    for (Map.Entry<? extends Enum<?>, Integer> e : union) {
        System.out.format("%4s (%3s) %2d%n",
                e.getKey(), e.getKey().getClass().getSimpleName(), e.getValue());
    }

输出为:

<块引用>
FOO1 (Foo)  2
FOO2 (Foo)  3
FOO3 (Foo)  8
BAR1 (Bar)  4
BAR2 (Bar)  6
BAR3 (Bar) 11

我正在使用如下所示的 IterableUnion 类。我认为它有一些通用性:您可以迭代两个以上的集合或其他实现 Iterable 的东西,并且元素类型可能会有所不同。

public class IterableUnion<E> implements Iterable<E> {

    private class UnionIterator implements Iterator<E> {
        private int index = 0;
        private Iterator<? extends E> iteratorForIndex;

        UnionIterator() {
            if (iterables.length > 0) {
                iteratorForIndex = iterables[0].iterator();
            }
        }
        
        @Override
        public boolean hasNext() {
            if (index == iterables.length) {
                return false;
            }
            while (true) {
                if (iteratorForIndex.hasNext()) {
                    return true;
                }
                index++;
                if (index == iterables.length) {
                    return false;
                }
                iteratorForIndex = iterables[index].iterator();
            }
        }

        @Override
        public E next() {
            if (! hasNext()) {
                throw new NoSuchElementException();
            }
            return iteratorForIndex.next();
        }
        
    }
    
    private final Iterable<? extends E>[] iterables;

    @SafeVarargs
    public IterableUnion(Iterable<? extends E>... iterables) {
        this.iterables = iterables;
    }
    
    @Override
    public Iterator<E> iterator() {
        return new UnionIterator();
    }

}