У меня была одна и та же проблема с выполнением заданий над кластером Mesos в режиме кластера.
Чтобы использовать драйвер JDBC, необходимо добавить зависимость к пути к системному классу не к пути класса framework. Я нашел способ сделать это, добавив зависимость в файл spark-defaults.conf
в каждом экземпляре кластера.
Добавляемые свойства: spark.driver.extraClassPath
и spark.executor.extraClassPath
, а путь должен находиться в локальной файловой системе.
В Java API такого класса нет. Класс Apache Commons, который вы хотите, будет одной из реализаций BidiMap .
Будучи математиком, я бы назвал такую структуру биекцией.
Вдохновленный ответом GETah Я решил написать что-то подобное себе с некоторыми улучшениями:
Map<K,V>
-Interface put
(по крайней мере, я надеюсь это гарантировать) Использование подобно обычной карте , чтобы получить обратный вид на картографический вызов getReverseView()
. Содержимое не копируется, возвращается только представление.
Я не уверен, что это абсолютно безупречно (на самом деле это, вероятно, нет), поэтому не стесняйтесь комментировать, если вы заметили какие-то недостатки и я 'll обновить ответ.
public class BidirectionalMap<Key, Value> implements Map<Key, Value> {
private final Map<Key, Value> map;
private final Map<Value, Key> revMap;
public BidirectionalMap() {
this(16, 0.75f);
}
public BidirectionalMap(int initialCapacity) {
this(initialCapacity, 0.75f);
}
public BidirectionalMap(int initialCapacity, float loadFactor) {
this.map = new HashMap<>(initialCapacity, loadFactor);
this.revMap = new HashMap<>(initialCapacity, loadFactor);
}
private BidirectionalMap(Map<Key, Value> map, Map<Value, Key> reverseMap) {
this.map = map;
this.revMap = reverseMap;
}
@Override
public void clear() {
map.clear();
revMap.clear();
}
@Override
public boolean containsKey(Object key) {
return map.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return revMap.containsKey(value);
}
@Override
public Set<java.util.Map.Entry<Key, Value>> entrySet() {
return Collections.unmodifiableSet(map.entrySet());
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public Set<Key> keySet() {
return Collections.unmodifiableSet(map.keySet());
}
@Override
public void putAll(Map<? extends Key, ? extends Value> m) {
m.entrySet().forEach(e -> put(e.getKey(), e.getValue()));
}
@Override
public int size() {
return map.size();
}
@Override
public Collection<Value> values() {
return Collections.unmodifiableCollection(map.values());
}
@Override
public Value get(Object key) {
return map.get(key);
}
@Override
public Value put(Key key, Value value) {
Value v = remove(key);
getReverseView().remove(value);
map.put(key, value);
revMap.put(value, key);
return v;
}
public Map<Value, Key> getReverseView() {
return new BidirectionalMap<>(revMap, map);
}
@Override
public Value remove(Object key) {
if (containsKey(key)) {
Value v = map.remove(key);
revMap.remove(v);
return v;
} else {
return null;
}
}
}
Здесь мои 2 цента.
Или вы можете использовать простой метод с дженериками. Кусок торта.
public static <K,V> Map<V, K> invertMap(Map<K, V> toInvert) {
Map<V, K> result = new HashMap<V, K>();
for(K k: toInvert.keySet()){
result.put(toInvert.get(k), k);
}
return result;
}
Конечно, у вас должна быть карта с уникальными значениями. В противном случае один из них будет заменен.
Вот простой класс, который я использовал, чтобы сделать это (я не хотел иметь еще одну зависимость от третьей стороны). Он не предлагает все функции, доступные на Картах, но это хороший старт.
public class BidirectionalMap<KeyType, ValueType>{
private Map<KeyType, ValueType> keyToValueMap = new ConcurrentHashMap<KeyType, ValueType>();
private Map<ValueType, KeyType> valueToKeyMap = new ConcurrentHashMap<ValueType, KeyType>();
synchronized public void put(KeyType key, ValueType value){
keyToValueMap.put(key, value);
valueToKeyMap.put(value, key);
}
synchronized public ValueType removeByKey(KeyType key){
ValueType removedValue = keyToValueMap.remove(key);
valueToKeyMap.remove(removedValue);
return removedValue;
}
synchronized public KeyType removeByValue(ValueType value){
KeyType removedKey = valueToKeyMap.remove(value);
keyToValueMap.remove(removedKey);
return removedKey;
}
public boolean containsKey(KeyType key){
return keyToValueMap.containsKey(key);
}
public boolean containsValue(ValueType value){
return keyToValueMap.containsValue(value);
}
public KeyType getKey(ValueType value){
return valueToKeyMap.get(value);
}
public ValueType get(KeyType key){
return keyToValueMap.get(key);
}
}
Если никаких столкновений не происходит, вы всегда можете добавить оба направления к одному и тому же HashMap: -)
Довольно старый вопрос здесь, но если у кого-то есть мозговой блок, как я только что сделал, и наткнулся на это, надеюсь, это поможет.
Я тоже искал двунаправленную HashMap, иногда это является самым простым из наиболее полезных ответов.
Если вы не хотите изобретать колесо и предпочитаете не добавлять в проект другие библиотеки или проекты, как насчет простой реализации параллельных массивов (или ArrayLists, если ваш проект требует этого).
SomeType[] keys1 = new SomeType[NUM_PAIRS];
OtherType[] keys2 = new OtherType[NUM_PAIRS];
Как только вы знаете индекс 1 из двух ключей, вы можете легко запросить другой. Таким образом, ваши методы поиска выглядят примерно так:
SomeType getKey1(OtherType ot);
SomeType getKey1ByIndex(int key2Idx);
OtherType getKey2(SomeType st);
OtherType getKey2ByIndex(int key2Idx);
Предполагается, что вы используете подходящие объектно-ориентированные структуры, где только методы модифицируют эти массивы / ArrayLists, было бы очень просто поддерживать их параллель. Еще проще для ArrayList, так как вам не придется перестраивать, если размер массивов изменяется, если вы добавляете / удаляете в тандеме.