甚至可能吗?
说你有
private Set<String> names = new LinkedHashSet<String>();
和Strings
是“迈克”,“约翰”,“凯伦”。
是否有可能在没有迭代的情况下获得“1”以回答“约翰”的索引是什么?
以下工作正常..有了这个问题,我想知道是否有更好的方法
for (String s : names) {
++i;
if (s.equals(someRandomInputString)) {
break;
}
}
答案 0 :(得分:22)
Set
interface没有像indexOf()
方法那样的东西。您确实需要对其进行迭代或使用提供List
interface的indexOf()
method代替。
如果您愿意,将Set
转换为List
非常简单,那么应该将Set
传递给List
实施的构造函数。 E.g。
List<String> nameList = new ArrayList<String>(nameSet);
// ...
答案 1 :(得分:4)
这是一个执行插入,删除,保留,由arraylist支持在get(index)上实现o(1)的实现。
/**
* @Author Mo. Joseph
*
* Allows you to call get with o(1) instead of o(n) to get an instance by index
*/
public static final class $IndexLinkedHashSet<E> extends LinkedHashSet<E> {
private final ArrayList<E> list = new ArrayList<>();
public $IndexLinkedHashSet(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
}
public $IndexLinkedHashSet() {
super();
}
public $IndexLinkedHashSet(int initialCapacity) {
super(initialCapacity);
}
public $IndexLinkedHashSet(Collection<? extends E> c) {
super(c);
}
@Override
public synchronized boolean add(E e) {
if ( super.add(e) ) {
return list.add(e);
}
return false;
}
@Override
public synchronized boolean remove(Object o) {
if ( super.remove(o) ) {
return list.remove(o);
}
return false;
}
@Override
public synchronized void clear() {
super.clear();
list.clear();
}
public synchronized E get(int index) {
return list.get(index);
}
@Override
public synchronized boolean removeAll(Collection<?> c) {
if ( super.removeAll(c) ) {
return list.removeAll(c);
}
return true;
}
@Override
public synchronized boolean retainAll(Collection<?> c) {
if ( super.retainAll(c) ) {
return list.retainAll(c);
}
return false;
}
/**
* Copied from super class
*/
@Override
public synchronized boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
}
测试它:
public static void main(String[] args) {
$IndexLinkedHashSet<String> abc = new $IndexLinkedHashSet<String>();
abc.add("8");
abc.add("8");
abc.add("8");
abc.add("2");
abc.add("3");
abc.add("4");
abc.add("1");
abc.add("5");
abc.add("8");
System.out.println("Size: " + abc.size());
int i = 0;
while ( i < abc.size()) {
System.out.println( abc.get(i) );
i++;
}
abc.remove("8");
abc.remove("5");
System.out.println("Size: " + abc.size());
i = 0;
while ( i < abc.size()) {
System.out.println( abc.get(i) );
i++;
}
abc.clear();
System.out.println("Size: " + abc.size());
i = 0;
while ( i < abc.size()) {
System.out.println( abc.get(i) );
i++;
}
}
哪个输出:
Size: 6
8
2
3
4
1
5
Size: 4
2
3
4
1
Size: 0
Ofcourse remove,removeAll,retainAll现在具有与ArrayList相同或更差的性能。但我不使用它们,所以我对此感到满意。
享受!
修改强>
这是另一个实现,它不会扩展LinkedHashSet,因为它是多余的。相反,它使用HashSet和ArrayList。
/**
* @Author Mo. Joseph
*
* Allows you to call get with o(1) instead of o(n) to get an instance by index
*/
public static final class $IndexLinkedHashSet<E> implements Set<E> {
private final ArrayList<E> list = new ArrayList<>( );
private final HashSet<E> set = new HashSet<> ( );
public synchronized boolean add(E e) {
if ( set.add(e) ) {
return list.add(e);
}
return false;
}
public synchronized boolean remove(Object o) {
if ( set.remove(o) ) {
return list.remove(o);
}
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return set.containsAll(c);
}
public synchronized void clear() {
set.clear();
list.clear();
}
public synchronized E get(int index) {
return list.get(index);
}
public synchronized boolean removeAll(Collection<?> c) {
if ( set.removeAll(c) ) {
return list.removeAll(c);
}
return true;
}
public synchronized boolean retainAll(Collection<?> c) {
if ( set.retainAll(c) ) {
return list.retainAll(c);
}
return false;
}
public synchronized boolean addAll(Collection<? extends E> c) {
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
@Override
public synchronized int size() {
return set.size();
}
@Override
public synchronized boolean isEmpty() {
return set.isEmpty();
}
@Override
public synchronized boolean contains(Object o) {
return set.contains(o);
}
@Override
public synchronized Iterator<E> iterator() {
return list.iterator();
}
@Override
public synchronized Object[] toArray() {
return list.toArray();
}
@Override
public synchronized <T> T[] toArray(T[] a) {
return list.toArray(a);
}
}
现在你有两个实现,我更喜欢第二个。
答案 2 :(得分:3)
我不相信,但你可以创建一个LinkedHashSetWithIndex
包装类来为你做迭代,或者保留一个单独的表与每个条目的索引,如果性能下降是可以接受的用例。
答案 3 :(得分:3)
Set通常不可能返回索引,因为它不一定为特定的Set实现定义良好。例如,它在HashSet文档中说明
它不保证集合的迭代顺序;特别是,它不保证订单会随着时间的推移保持不变。
因此,当您实际期望的是Set实现som顺序时,您不应该说类型是Set。
答案 4 :(得分:2)
虽然对机器效率不高,但这可以在一行中实现:
int index = new ArrayList<String>(names).indexOf("John");
答案 5 :(得分:2)
Set
是“不包含重复元素的集合”,并且它不维护其元素的顺序。 http://download.oracle.com/javase/6/docs/api/java/util/Set.html
您提供的代码不一定每次都返回1。迭代Set
并不能保证每次都以相同的顺序迭代;它只能保证迭代每个元素一次。
由于您似乎关心元素的顺序,因此您需要使用List
而不是Set
。
答案 6 :(得分:0)
没有更好的方法,只有一个内衬的(它也使用了迭代器,但是隐式):
new ArrayList(names).get(0)
答案 7 :(得分:0)
我不确定代码的质量,但是对我来说有用。
您可以将“集合”转换为“列表”,然后可以执行任何索引操作。
示例:需要将“设置列表”裁剪为5个项目。
Set<String> listAsLinkedHashSet = new LinkedHashSet<>();
listAsLinkedHashSet.add("1");
listAsLinkedHashSet.add("2");
listAsLinkedHashSet.add("3");
listAsLinkedHashSet.add("4");
listAsLinkedHashSet.add("1");
listAsLinkedHashSet.add("2");
listAsLinkedHashSet.add("5");
listAsLinkedHashSet.add("7");
listAsLinkedHashSet.add("9");
listAsLinkedHashSet.add("8");
listAsLinkedHashSet.add("1");
listAsLinkedHashSet.add("10");
listAsLinkedHashSet.add("11");
List<String> listAsArrayList = new ArrayList<>(listAsLinkedHashSet);
//crop list to 5 elements
if (listAsArrayList.size() > 5) {
for (int i = 5; i < listAsArrayList.size(); i++) {
listAsArrayList.remove(i);
i--;
}
}
listAsLinkedHashSet.clear();
listAsLinkedHashSet.addAll(listAsArrayList);