Java - 从列表中获取对象?

时间:2014-08-05 11:38:00

标签: java performance list collections

大家好,

在开发我的项目时,我实现了这样的场景。我有一个LinkedList,其中包含100 学生类对象。

我的方案是,

我需要从LinkedList rollNo = 98 中获取一个特定的学生类对象。所以我使用了下面的代码。

我的pojo课程是,

public class Student {

    private int rollNo ;
    private String name;

    // getters & setters        
}

我的主要课程是,

public class MainClass {

    List<Student> list = null;

    public MainClass(){
        list = new LinkedList<Student>();
    }

    public static void main(String... args){
        MainClass mainClass = new MainClass();
        mainClass.addStudentDetail();
        Student obj = mainClass.getStudentObject(98);

        // other Stuff with obj
    }

    private void addStudentDetail() {
        for(int i=1; i<=100; i++){
            Student obj = new Student();
            obj.setRollNo(i);
            obj.setName("Name"+i);
            list.add(obj);
        }

    }

    private Student getStudentObject(int rollNo) {
        int listLength = list.size();

        for(int i=0; i<listLength; i++){

            if(list.get(i).getRollNo() == rollNo)
                return list.get(i);

        }
        return null;
    }
}

要获取Student对象,其中rollNo = 98,

这需要98 iterations

那么如果我的列表大小 1,00,000 会发生什么?我需要{strong> rollNo = 99,999 的Student对象?

是否有其他简单方法可以使用where condition获取一个特定对象?

注意:

很抱歉,我不需要将HashMap rollNo 一起使用作为密钥。我的需要是只使用LinkedList。这是我的要求。

希望我能在这里得到一个好的解决方案。

8 个答案:

答案 0 :(得分:4)

使用Map rollNo作为键,Student实例作为值。这是&#34; index&#34;的常用方法。这样的集合使查找尽可能高效

更新:

如果您想快速搜索,则需要某种索引。查看Java的HashMap源代码,看看如何存储密钥,这可能会让您对案例有所了解

答案 1 :(得分:1)

如果您使用LinkedList,那么它需要98次迭代才能找到学生。您可以使用地图,并按键找到学生。键可以是rollNo,也可以是学生自己的值。

答案 2 :(得分:1)

在java中,主要使用两种类型的列表,它们是 ArrayList LinkedList 。两者都保留数据插入List的顺序。所以在这种情况下没有其他方法,你必须逐个迭代。

替代解决方案设置。经常使用三种类型的集合,它们是TreeSet,HashSet和LinkedHashSet。

LinkedHashSet :保留插入数据集的顺序。 (在你的情况下没用)。搜索将在O(n)。

TreeSet :它在内部维护红黑树中的数据。所以搜索会很快。搜索将在O(log n)。

HashSet :它在内部维护HashMap中的数据。因此搜索将比TreeSet快得多。搜索将在O(1)。

答案 3 :(得分:0)

由于地图不在等式中而您需要使用列表,因此您最终会进行那么多次迭代。或者,您可以对列表进行排序并实现类似逻辑的二进制搜索,以获得更好的性但是,如果您对List不是很了解,可以使用HashSet。它在大多数方面类似于列表,但只能包含唯一值。文档说这个类为基本操作(添加,删除,包含和大小)提供恒定的时间性能。但为此,您需要覆盖与rollNo相关的equals和hashCode方法。实施例

public class Student {

    private int rollNo;
    private String name;

    //Getters & Setters.

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + rollNo;
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (rollNo != other.rollNo)
            return false;
        return true;
    }
}

答案 4 :(得分:0)

好吧,如果你需要使用LinkedList,为了提高性能,我唯一想到的就是将列表的大小除以2,并检查你正在寻找的索引for是在上限或下限范围内。

如果它在上半部分,则使用descendingIterator()以相反的顺序迭代集合。如果它在下半部分,则使用正常iterator。它不会提高它的性能,但至少当你想要一个上半部分的对象时,你会节省很多次迭代。毕竟,这是一个双重链表。

但是,我会使用Map的实现,但由于你不能这样做,试试我所解释的。

答案 5 :(得分:0)

看起来roll no是唯一的。为什么不将它用作链表中的索引呢?将98卷没有对象放在链表的第98个索引中。

顺便说一下hashmap也没关系。虽然如果roll no是唯一的,那么上述方式在内存上既快又便宜。

答案 6 :(得分:0)

由于您目前通过简单的for循环添加学生,所有学生都很好,整齐排序。所以你可以说,位置x的学生的卷号是x + 1。

但现在想象一下,有些学生会离开而有些人会来。过了一段时间,&#34; x + 1&#34;不再起作用了。甚至连序列都不会再成为现实。所以它不再是1,2,3,而是2,3,1?

在具有> 1百万条目的集合上进行迭代,排序等是没用的。

您需要做的是:使用数据库! 如果您不能使用基于服务器的数据库,您也可以使用SQLite或类似的。

然后,您可以通过简单的SQL语句访问卷号为99(或943,251)的学生记录,并将结果解析为Student实例。

在我看来,这是保持代码相对容易和小的最快方法。

答案 7 :(得分:0)

如果您仅限于LinkedList,则可以通过不使用get(i)循环来升级代码。这种方法非常低效,因为如

中所述

Why would iterating over a List be faster than indexing through it?

每个get(i)从列表的开头迭代到i-th元素,如

得(0) - item0
得到(1) - item0 -> item1
得到(2) - item0 -> item1 -> item2
得到(3) - item0 -> item1 -> item2 -> item3

您应该使用Iterator及其next方法来获取基于前一个元素的下一个元素,而不是这种方法。代码如

Iterator<Student> it = list.iterator();
while ( it.hasNext() ){
    Student s = i.next();
    //handle s here - test it or something
}

会以这种方式迭代

 next       next       next       next 
  ->  item0  ->  item1  ->  item2  ->  item3

而不是

get(0)    get(1)            get(2)                    get(3)
  -> item0  -> (item0->item1) -> (item0->item1->item2) -> (item0->item1->item2->item3)

上面的BTW代码也可以使用for-each loop编写

for (Student s : list){
    //handle s here
}

所以改变你的

for(int i=0; i<listLength; i++){
    if(list.get(i).getRollNo() == rollNo)
        return list.get(i);

for(String s : list)
    if (s.getRollNo() == rollNo)
        return s;

如果您确定该列表是有序的,那么您可以通过使用ListIteratot及其previous方法(如

)从其末尾迭代来提高更接近列表大小的元素的搜索性能
ListIterator<String> it = list.listIterator(list.size());
while(it.hasPrevious())
    System.out.println(it.previous());