如果有人熟悉Objective-C,则有一个名为NSOrderedSet
的集合充当集,其项目可以作为数组进行访问的。
Java中有这样的东西吗?
我听说有一个名为LinkedHashMap
的集合,但我没有找到类似的集合。
答案 0 :(得分:103)
查看LinkedHashSet班级
答案 1 :(得分:29)
每个Set都有一个迭代器()。普通的HashSet迭代器是随机的,TreeSet按排序顺序执行,LinkedHashSet迭代器按插入顺序迭代。
但是,您无法替换LinkedHashSet中的元素。您可以删除一个并添加另一个,但新元素不会替换原始元素。在LinkedHashMap中,您可以替换现有键的值,然后值仍将保持原始顺序。
此外,您无法插入某个位置。
也许你最好使用带有显式检查的ArrayList,以避免插入重复项。
答案 2 :(得分:10)
看看Java standard API doc。在LinkedHashMap
旁边,有一个LinkedHashSet
。但请注意,那些顺序是插入顺序,而不是元素的自然顺序。并且您只能按该顺序迭代,而不是随机访问(除非通过计算迭代步骤)。
还有SortedSet
和TreeSet
实施的界面ConcurrentSkipListSet
。两者都允许在元素的natural order或Comparator
中进行迭代,但不能随机访问或插入顺序。
对于既能通过索引进行高效访问又能有效实现set标准的数据结构,您需要skip list,但Java Standard API中没有该功能的实现,虽然我确信在互联网上找到一个很容易。
答案 3 :(得分:4)
答案 4 :(得分:4)
尝试使用实现java.util.TreeSet
的SortedSet
。
引用文档:
“元素是按照自然顺序排序的,或者是在创建时设置的比较器,具体取决于使用的构造函数”
请注意,添加,删除和包含时间成本日志(n)。
如果要将集合的内容作为数组访问,可以将其转换为:
YourType[] array = someSet.toArray(new YourType[yourSet.size()]);
此数组将使用与TreeSet(自然或比较器)相同的条件进行排序,在许多情况下,这将有一个优势,而不是执行Arrays.sort()
答案 5 :(得分:1)
treeset是一个有序集,但您无法通过项索引进行访问,只需遍历或进入开始/结束。
答案 6 :(得分:0)
如果我们谈论跳过列表的廉价实现,我想知道对于大O来说,这个操作的成本是多少:
YourType [] array = someSet.toArray(new YourType [yourSet.size()]);
我的意思是它总是陷入整个数组创建,所以它是O(n):
java.util.Arrays#copyOf
答案 7 :(得分:0)
indexed-tree-map提供了此功能(按索引进行列表式访问的有序/有序集)。
答案 8 :(得分:0)
您也可以从双向地图中获取一些实用工具,例如来自BiMap
的Google Guava
使用BiMap
,您可以非常有效地将Integer(用于随机索引访问)映射到任何其他对象类型。 BiMap
是一对一的,因此任何给定的整数最多只有一个与之关联的元素,并且任何元素都有一个关联的整数。它由两个HashTable
实例巧妙地支持,因此它几乎使用了两倍的内存,但就处理而言,它比自定义List
效率更高,因为{{1} (在添加项目时调用它以检查它是否已存在)是一个恒定时间和并行友好的操作,如contains()
' s,HashSet
' s实施速度很慢。
答案 9 :(得分:0)
我有类似的问题。我不太需要一个有序集,但更多的是一个快速indexOf
/ contains
的列表。由于我没有找到任何东西,我自己实施了一个。这是代码,它实现了Set
和List
,但并非所有批量列表操作都与ArrayList
版本一样快。
免责声明:未经过测试
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.Collection;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
import static java.util.Objects.requireNonNull;
/**
* An ArrayList that keeps an index of its content so that contains()/indexOf() are fast. Duplicate entries are
* ignored as most other java Set's do.
*/
public class IndexedArraySet<E> extends ArrayList<E> implements Set<E> {
public IndexedArraySet() { super(); }
public IndexedArraySet(Iterable<E> c) {
super();
addAll(c);
}
private HashMap<E, Integer> indexMap = new HashMap<>();
private void reindex() {
indexMap.clear();
int idx = 0;
for (E item: this) {
addToIndex(item, idx++);
}
}
private E addToIndex(E e, int idx) {
indexMap.putIfAbsent(requireNonNull(e), idx);
return e;
}
@Override
public boolean add(E e) {
if(indexMap.putIfAbsent(requireNonNull(e), size()) != null) return false;
super.add(e);
return true;
}
@Override
public boolean addAll(Collection<? extends E> c) {
return addAll((Iterable<? extends E>) c);
}
public boolean addAll(Iterable<? extends E> c) {
boolean rv = false;
for (E item: c) {
rv |= add(item);
}
return rv;
}
@Override
public boolean contains(Object e) {
return indexMap.containsKey(e);
}
@Override
public int indexOf(Object e) {
if (e == null) return -1;
Integer i = indexMap.get(e);
return (i == null) ? -1 : i;
}
@Override
public int lastIndexOf(Object e) {
return indexOf(e);
}
@Override @SuppressWarnings("unchecked")
public Object clone() {
IndexedArraySet clone = (IndexedArraySet) super.clone();
clone.indexMap = (HashMap) indexMap.clone();
return clone;
}
@Override
public void add(int idx, E e) {
if(indexMap.putIfAbsent(requireNonNull(e), -1) != null) return;
super.add(idx, e);
reindex();
}
@Override
public boolean remove(Object e) {
boolean rv;
try { rv = super.remove(e); }
finally { reindex(); }
return rv;
}
@Override
public void clear() {
super.clear();
indexMap.clear();
}
@Override
public boolean addAll(int idx, Collection<? extends E> c) {
boolean rv;
try {
for(E item : c) {
// check uniqueness
addToIndex(item, -1);
}
rv = super.addAll(idx, c);
} finally {
reindex();
}
return rv;
}
@Override
public boolean removeAll(Collection<?> c) {
boolean rv;
try { rv = super.removeAll(c); }
finally { reindex(); }
return rv;
}
@Override
public boolean retainAll(Collection<?> c) {
boolean rv;
try { rv = super.retainAll(c); }
finally { reindex(); }
return rv;
}
@Override
public boolean removeIf(Predicate<? super E> filter) {
boolean rv;
try { rv = super.removeIf(filter); }
finally { reindex(); }
return rv;
}
@Override
public void replaceAll(final UnaryOperator<E> operator) {
indexMap.clear();
try {
int duplicates = 0;
for (int i = 0; i < size(); i++) {
E newval = requireNonNull(operator.apply(this.get(i)));
if(indexMap.putIfAbsent(newval, i-duplicates) == null) {
super.set(i-duplicates, newval);
} else {
duplicates++;
}
}
removeRange(size()-duplicates, size());
} catch (Exception ex) {
// If there's an exception the indexMap will be inconsistent
reindex();
throw ex;
}
}
@Override
public void sort(Comparator<? super E> c) {
try { super.sort(c); }
finally { reindex(); }
}
}