Подтвердить что ты не робот

Какая хорошая постоянная структура коллекций для использования в java?

С помощью постоянных коллекций я имею в виду такие же коллекции, как в clojure.

Например, у меня есть список с элементами (a, b, c). С обычным списком, если я добавлю d, мой исходный список будет иметь (a, b, c, d) как его элементы. С постоянным списком, когда я вызываю list.add(d), я возвращаю новый список, удерживая (a, b, c, d). Тем не менее, реализация пытается обмениваться элементами между списком, где это возможно, поэтому он намного эффективнее памяти, чем просто возврат копии исходного списка. Это также имеет преимущество неизменного (если я держу ссылку на исходный список, тогда он всегда будет возвращать исходные 3 элемента).

Все это объясняется намного лучше в другом месте (например, http://en.wikipedia.org/wiki/Persistent_data_structure).

В любом случае, мой вопрос... какая лучшая библиотека для предоставления этой функции для использования в java? Можно ли каким-либо образом использовать коллекции clojure (другие, которые напрямую используются clojure)?

4b9b3361

Ответ 1

Просто используйте те, что находятся в Clojure. Хотя очевидно, что вы, возможно, не захотите использовать язык самостоятельно, вы все равно можете использовать постоянные коллекции напрямую, поскольку все они являются только классами Java.

import clojure.lang.PersistentHashMap;
import clojure.lang.IPersistentMap;

IPersistentMap map = PersistentHashMap.create("key1", "value1");

assert map.get("key1").equals("value1");
IPersistentMap map2 = map.assoc("key1", "value1");

assert map2 != map;
assert map2.get("key1").equals("value1");

(отказ от ответственности: я на самом деле не скомпилировал этот код:)

нижняя сторона состоит в том, что коллекции не набираются, т.е. с ними нет дженериков.

Ответ 3

Я искал тонкий, "дружественный" Java постоянный фреймворк для коллекций и взял TotallyLazy и PCollections, упомянутые в этой теме, для тест-драйва, потому что они показались мне многообещающими.

Оба предоставляют разумные простые интерфейсы для управления постоянными списками:

// TotallyLazy
PersistentList<String> original = PersistentList.constructors.empty(String.class);
PersistentList<String> modified = original.append("Mars").append("Raider").delete("Raider");

// PCollections
PVector<String> original = TreePVector.<String>empty();
PVector<String> modified = original.plus("Mars").plus("Raider").minus("Raider");

Оба PersistentList и PVector расширяют java.util.List, поэтому обе библиотеки должны хорошо интегрироваться в существующую среду.

Однако оказывается, что TotallyLazy сталкивается с проблемами с производительностью при работе с большими списками (как уже упоминалось в комментарии выше @levantpied). На моем MacBook Pro (конец 2013 г.) для вставки 100 000 элементов и возврата неизменяемого списка потребовалось TotallyLazy ~ 2000 мс, в то время как PCollections закончили через ~ 120 мс.

Мои (простые) тестовые случаи доступны на Bitbucket, если кто-то хочет взглянуть более тщательно.

[ОБНОВЛЕНИЕ]: Недавно я взглянул на Cyclops X, который является высокопроизводительной и более полной библиотекой, предназначенной для функционального программирования. Циклоп также содержит модуль для постоянных коллекций.

Ответ 4

https://github.com/andrewoma/dexx является портом Scala постоянных коллекций для Java. Он включает в себя:

  • Set, SortedSet, Map, SortedMap и Vector
  • Адаптеры для просмотра постоянных коллекций как эквиваленты java.util
  • Помощники для легкой конструкции

Ответ 5

Может захотеть проверить clj-ds. Я не использовал его, но он кажется многообещающим. Исходя из проектов readme, они извлекли структуры данных из Clojure 1.2.0.

Ответ 6

Функциональная Java реализует постоянный список, ленивый список, набор, карту и дерево. Могут быть и другие, но я просто просматриваю информацию на первой странице сайта.

Мне также интересно узнать, какая лучшая постоянная библиотека структуры данных для Java. Мое внимание было обращено на функциональную Java, потому что в книге упоминается "Функциональное программирование для разработчиков Java" .

Ответ 7

Там pcollections (постоянная коллекция) библиотека, которую вы можете использовать:

http://code.google.com/p/pcollections/

Ответ 8

Главный голосовой ответ предлагает напрямую использовать коллекции clojure, которые я считаю очень хорошей идеей. К сожалению, тот факт, что clojure является динамически типизированным языком, а Java не делает библиотеки clojure очень неудобными для использования в Java.

Из-за этого и отсутствия легких, простых в использовании оболочек для типов коллекций clojure я написал свою собственную библиотеку оболочек Java с использованием дженериков для типов коллекций clojure с уделением особого внимания использования и ясности, когда дело доходит до интерфейсов.

https://github.com/cornim/ClojureCollections

Возможно, это будет полезно для кого-то.

P.S.: На данный момент реализованы только PersistentVector, PersistentMap и PersistentList.

Ответ 9

Paguro предоставляет безопасные версии фактических коллекций Clojure для использования в Java 8+. Он включает в себя: Список (Вектор), HashMap, TreeMap, HashSet и TreeSet. Они ведут себя точно так, как вы указываете в своем вопросе, и кропотливо вписываются в существующие интерфейсы коллекций java.util для максимальной совместимости с Java, Они также немного быстрее, чем PCollections.

Кодирование вашего примера в Paguro выглядит следующим образом:

// List with the elements (a,b,c)
ImList<T> list = vec(a,b,c);

// With a persistent list, when I call list.add(d),
// I get back a new list, holding (a,b,c,d)
ImList<T> newList = list.append(d);

list.size(); // still returns 3

newList.size(); // returns 4

Ты сказал,

Реализация пытается обмениваться элементами между списком везде, где это возможно, поэтому он намного эффективнее и быстрее памяти просто возвращая копию исходного списка. Он также имеет преимущество неизменного (если я держу ссылку на оригинал список, то он всегда будет возвращать исходные 3 элемента).

Да, это точно, как он себя ведет. Даниэль Спивак объясняет скорость и эффективность этих коллекций намного лучше, чем я мог.

Ответ 10

В том же духе, что и Корнелиус Мунд, Pure4J переносит коллекции Clojure в Java и добавляет поддержку Generics.

Однако Pure4J нацелен на внедрение чистой семантики программирования в JVM с помощью проверки кода времени компиляции, поэтому он идет дальше, чтобы ввести ограничения ограничений для ваших классов, так что элементы коллекции не могут быть мутированы, пока существует коллекция.

Это может быть или не быть тем, чего вы хотите достичь: если вы только после использования коллекций Clojure на JVM, я бы пошел с подходом Корнелиуса, в противном случае, если вы заинтересованы в реализации чистого программного подхода в рамках Java, тогда вы могли бы попробовать Pure4J.

Раскрытие информации: Я разработчик этого

Ответ 11

totallylazy - очень хорошая библиотека FP, которая имеет реализации:

  • PersistentList<T>: конкретные реализации LinkedList<T> и TreeList<T> (для произвольного доступа)
  • PersistentMap<K, V>: конкретные реализации HashTreeMap<K, V> и ListMap<K, V>
  • PersistentSortedMap<K, V>
  • PersistentSet<T>: конкретная реализация TreeSet<T>

Пример использования:

import static com.googlecode.totallylazy.collections.PersistentList.constructors.*;
import com.googlecode.totallylazy.collections.PersistentList;
import com.googlecode.totallylazy.numbers.Numbers;

...

PersistentList<Integer> list = list(1, 2, 3);

// Create a new list with 0 prepended
list = list.cons(0);

// Prints 0::1::2::3
System.out.println(list);

// Do some actions on this list (e.g. remove all even numbers)
list = list.filter(Numbers.odd);
// Prints 1::3
System.out.println(list);

Полнолазы постоянно поддерживаются. Основным недостатком является полное отсутствие Джавадока.

Ответ 12

Я удивлен, что никто не упомянул vavr. Я использую это в течение долгого времени.

http://www.vavr.io

Описание с их сайта:

Ядро Vavr - это функциональная библиотека для Java. Это помогает уменьшить объем кода и повысить надежность. Первый шаг к функциональному программированию - начать думать в неизменных ценностях. Vavr предоставляет неизменяемые коллекции и необходимые функции и управляющие структуры для работы с этими значениями. Результаты прекрасны и просто работают.

Ответ 13

https://github.com/arnohaase/a-foundation - это еще один порт библиотек Scala.

Он также доступен от Maven Central: com.ajjpj.a-foundation: a-foundation