Java:TreeMap是一种搜索重复字符串作为组合键一部分的好方法

robbie70:

我有一个TreeMap键是基于两个字段的组合键。我希望能够TreeMap仅在第二个键元素上搜索匹配项-可能有该元素的重复项。要说明我要做什么,请参阅以下内容,

public class CountySchoolsController {

    static TreeMap<StudentKey, Student> schoolsMap = new TreeMap<>();

    public static void main(String args[]) {
        createSchoolsTreeMap();
        System.out.println(schoolsMap.get(new StudentKey(1, "Holmes")));
    }

    private static TreeMap<StudentKey, Student> createSchoolsTreeMap() {
        Student s1 = new Student(1, "Sherlock", "Holmes");
        Student s2 = new Student(2, "John", "Watson");
        Student s3 = new Student(3, "Franklin", "Holmes");
        schoolsMap.put(new StudentKey(s1.getSchoolId(), s1.getLastname()), s1);
        schoolsMap.put(new StudentKey(s2.getSchoolId(), s2.getLastname()), s2);
        schoolsMap.put(new StudentKey(s3.getSchoolId(), s3.getLastname()), s3);
        return schoolsMap;
    }
}

public class StudentKey implements Comparable<StudentKey>{

    int schoolId;
    String lastname;

    public StudentKey(int id, String lastname){
        this.schoolId = id;
        this.lastname = lastname;
    }

    public int getSchoolId() {
        return schoolId;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        StudentKey that = (StudentKey) o;
        return schoolId == that.schoolId &&
                Objects.equals(lastname, that.lastname);
    }

    @Override
    public int hashCode() {
        return Objects.hash(schoolId, lastname);
    }

    @Override
    public int compareTo(StudentKey o) {
        return (this.schoolId + this.lastname).compareTo(o.schoolId + o.lastname);
    }
}

public class Student {

    int schoolId;
    String firstname;
    String lastname;

    public Student(int schoolId, String firstname, String lastname) {
        this.schoolId = schoolId;
        this.firstname = firstname;
        this.lastname = lastname;
    }

    public int getSchoolId() {
        return schoolId;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }

    @Override
    public String toString() {
        return "Student{" +
                "schoolId=" + schoolId +
                ", firstname='" + firstname + '\'' +
                ", lastname='" + lastname + '\'' +
                '}';
    }
}

当我运行此代码时,它运行良好并打印找到的内容Student

Student{schoolId=1, firstname='Sherlock', lastname='Holmes'}

但是,我想做的就是只搜索lastnamefor Holmes并返回两个由ID 1和3表示的记录。除了像这样进行搜索外,我还需要能够对键的精确匹配进行搜索(如在上面的示例中)。

理想情况下,如果可以使用wildcardfor 会很好schoolId但我认为这是不可能的。

我可以返回键集值并对其进行迭代以仅在上找到匹配项,lastname但我认为这样做的效果不是很好-请告诉我您是否不同意,或者这是否是实现此目标的最佳方法?还是我应该以其他方式实施?

WJS:

试试这个。它流式传输entrySet地图的,仅过滤姓氏,然后映射到与该名称关联的值并将其放在列表中。我不得不做出的lastname领域public这一点。投入getters的领域将是有益的。


        List<Student> list = schoolsMap.entrySet().stream()
                .filter(e -> e.getKey().lastname
                        .equals("Holmes"))
                .map(Entry::getValue)
                .collect(Collectors.toList());


        list.forEach(System.out::println);

我决定在这方面走得更远。如果将getters所有key属性都放在StudentKey类中,则可以执行以下操作:

获取所有的姓氏 Holmes

      List<Student> names = getStudentsForKeyAttribute(
                StudentKey::getLastName, "Holmes");

      names.forEach(System.out::println);

让学生参加 id = 3


      List<Student> ids = getStudentsForKeyAttribute(StudentKey::getSchoolId, 3);

      ids.forEach(System.out.println); 

以下方法接受一个AttributeExtractor函数,从中提取适当的属性StudentKey,然后根据提供的参数进行过滤。

        public <T> List<Student> getStudentsForKeyAttribute(
            Function<StudentKey, T> attrExtractor, T keyAttribute) {
            return schoolsMap.entrySet().stream()
                .filter(e -> attrExtractor.apply(e.getKey())
                        .equals(keyAttribute))
                .map(Entry::getValue)
                .collect(Collectors.toList());
        }

重要编辑:我添加了数据保留功能。第一次通过每个属性时,它将为该属性构建映射并返回请求的值。将来的通话将使用现有地图。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.TreeMap;
import java.util.function.Function;


// Main attribute for lookup
enum Attribute {
    LASTNAME, GENDER
}

// subattribute for gender.  For lastname it would jut be a name.
// I decided to use an enum for gender.
enum Gender {
    M, F, O
};

public class CompositeSearch {
    // Map of map.
    // Example:
    //   Outer Map is for LastName attribute
    //   Inner map as all lists for common last names.  All names are included.
    //     I had to use an Object to allow for different types (enums, strings, ints)
    Map<Attribute, Map<Object, List<Student>>> studentsByAttribute = new HashMap<>();


    // this provides an extractor for each type requested. It just maps the 
    // Attribute to the Student Key method call for that type.
    Map<Attribute, Function<StudentKey, ?>> extractorsForType = new HashMap<>() {
        {
            put(Attribute.LASTNAME,
                    StudentKey::getLastName);
            put(Attribute.GENDER, StudentKey::getGender);
        }
    };

    // intiial data base
    TreeMap<StudentKey, Student> schoolsMap = new TreeMap<>();

    public static void main(String args[]) {
        new CompositeSearch().start();
    }

    public void start() {
        createSchoolsTreeMap();

        // getting all female students.
        List<Student> list = getStudentsForKeyAttribute(
                Attribute.GENDER, Gender.F);

        list.forEach(System.out::println);
        System.out.println();

        // getting all students with last name of holmes.
        list = getStudentsForKeyAttribute(Attribute.LASTNAME, "Holmes");
        list.forEach(System.out::println);

        // All maps for Gender and lastnames have been created so 
        // the lookups below require two map retrievals.  The attribute and the 
        // sub attribute
        System.out.println();
        list = getStudentsForKeyAttribute(
                Attribute.GENDER, Gender.M);

        list.forEach(System.out::println);
        System.out.println();

        list = getStudentsForKeyAttribute(Attribute.LASTNAME, "Watson");
        list.forEach(System.out::println);


    }

    public <T> List<Student> getStudentsForKeyAttribute(
            Attribute attr, T keyAttribute) {

        @SuppressWarnings("unchecked")
        Function<StudentKey, T> extractor = (Function<StudentKey, T>) extractorsForType
                .get(attr);

        if (!studentsByAttribute.containsKey(attr)) {
            // need to create the map.
            System.out.println("Building map for all " + attr);
            // sub attribute map
            Map<Object, List<Student>> subMap = new HashMap<>();

            studentsByAttribute.put(attr, subMap);

            for (Map.Entry<StudentKey, ?> e : schoolsMap
                    .entrySet()) {
              T subAttribute = extractor.apply(e.getKey());

                            subMap.compute(subAttribute,
                                    (k, v) -> v == null
                                            ?  new ArrayList<>()
                                            : v)
                            .add((Student)e.getValue());

            }
        } else {
            System.out.println("Using existing map for all " + attr);
        }
        return studentsByAttribute.get(attr).get(keyAttribute);

    }

    // from here on out, everything is pretty normal.
    private TreeMap<StudentKey, Student> createSchoolsTreeMap() {
        List<Student> students = List.of(
                new Student(1, "Sherlock", "Holmes",
                        Gender.M),
                new Student(2, "John", "Watson", Gender.M),
                new Student(3, "Franklin", "Holmes",
                        Gender.M),
                new Student(4, "Frances", "Holmes",
                        Gender.F),
                new Student(5, "Mary", "Wilson", Gender.F),
                new Student(6, "Martha", "Watson",
                        Gender.F));
        for (Student s : students) {
            schoolsMap.put(new StudentKey(s), s);
        }

        return schoolsMap;
    }

}

class StudentKey implements Comparable<StudentKey> {

    private int schoolId;
    private String lastname;
    private Gender gender;

    public StudentKey(Student student) {
        this.schoolId = student.getSchoolId();
        this.lastname = student.getLastname();
        this.gender = student.getGender();
    }

    public int getSchoolId() {
        return schoolId;
    }

    public String getLastName() {
        return lastname;
    }

    public Gender getGender() {
        return gender;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o)
            return true;
        if (o == null || getClass() != o.getClass())
            return false;
        StudentKey that = (StudentKey) o;
        return schoolId == that.schoolId
                && Objects.equals(lastname, that.lastname);
    }

    @Override
    public int hashCode() {
        return Objects.hash(schoolId, lastname);
    }

    @Override
    public int compareTo(StudentKey o) {
        return (this.schoolId + this.lastname)
                .compareTo(o.schoolId + o.lastname);
    }

}

class Student {

    int schoolId;
    String firstname;
    String lastname;
    Gender gender;

    public Student(int schoolId, String firstname,
            String lastname, Gender gender) {
        this.schoolId = schoolId;
        this.firstname = firstname;
        this.lastname = lastname;
        this.gender = gender;
    }

    public int getSchoolId() {
        return schoolId;
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public Gender getGender() {
        return gender;
    }

    @Override
    public String toString() {
        return "Student{" + "schoolId=" + schoolId
                + ", firstname='" + firstname + '\''
                + ", lastname='" + lastname + '\'' + '}';
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章