2

I think it quite simple but I need one ways to solve it easy.

My problem is: I have list object Student include 100 objects

public class Student {

private String id;
private String name;
private int age;


public String getId() {
    return id;
}
public void setId(String id) {
    this.id = id;
}

public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}

public int getAge() {
    return age;
}
public void setAge(int age) {
    this.age = age;
}

Now, I only want to get age of some student has name "ABC", "BCD", "DEF"

So I will do it:

Map<String, String> data = new HashMap<>();
    List<String> listSpecification = new ArrayList<>(Arrays.asList("ABC", "BCD", "DEF"));
    for (Student stu : list<Student>) {
        for (int i = 0; i < listSpecification.size(); i++) {
            if (stu.getName().equalsIgnoreCase(listSpecification.get(i))) {
                data.put(pro.getName(), pro.getValue());
            }
        }
    }

But if I do it, I think it not good about performance. So anyone can help me another case ?

Tran Vinh Quang
  • 585
  • 2
  • 9
  • 30

2 Answers2

5

Your algorithm has complexity O(m*n) where m is the number of students and n is the number of names. The suggestions to use streaming APIs or Collection.contains won't change that.

You can convert this to an O(m + n) algorithm by using a map from student name to Student:

Map<String, Student> studentsByName = new HashMap<>();
for (Student s : studentList) {
    studentsByName.put(s.getName().toLowerCase(), s);
}

That's an O(m) operation. Then you can iterate through all the names in the specification list, convert each to lower case, and pull out each student directly. This is an O(n) operation. There's a further efficiency in that you need do the first step only once if you need to process multiple specification lists for the same student list.

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • So, After I get map studentsByName. I must use 2 times for loop to get list student I want ? Is this correct or I miss something ? – Tran Vinh Quang Dec 04 '15 at 05:37
  • @QuangTV - With this approach, you loop once through the students to build the map. Then you use a second loop to go through the names in the specification. You only need to loop one time (for each specification list) after mapping the students by name. – Ted Hopp Dec 04 '15 at 05:39
2

Basically you have little choice, you need to compare each element in the Student's List with each value in the listSpecification List.

You could use listSpecification.contains(stu.getName()), but you would need to guarantee the case requirements (maybe by making everything all upper case)

Another approach could be to make use of the new Stream API available in Java 8

List<String> listSpecification = new ArrayList<>(Arrays.asList("ABC", "BCD", "DEF"));

List<Student> students = new ArrayList<>();
students.add(new Student("0", "ABC", 0));
students.add(new Student("1", "XYZ", 0));
students.add(new Student("2", "HIJ", 0));
students.add(new Student("3", "LMN", 0));
students.add(new Student("4", "OPQ", 0));
students.add(new Student("5", "BCD", 0));
students.add(new Student("6", "EFG", 0));
students.add(new Student("7", "HIJ", 0));
students.add(new Student("8", "DEF", 0));
students.add(new Student("9", "STY", 0));

List<Student> matches = students.stream().filter((Student t) -> listSpecification.contains(t.getName())).collect(Collectors.toList());
System.out.println(matches);

But, again, you would need to ensure that the String case matched (maybe by making the listSpecification all uppercase and using t.getName().toUpperCase()

Is it more efficient? I'd doubt it, but you'd have to some serious comparisons to be sure.

Another technique might be to build a series of Maps which key certain values (like the name) to the instances of Student, as an example, but you'd need to provide more context to the overall problem to know if it was worth the effort or not

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366