我有一个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'}
但是,我想做的就是只搜索lastname
for Holmes
并返回两个由ID 1和3表示的记录。除了像这样进行搜索外,我还需要能够对键的精确匹配进行搜索(如在上面的示例中)。
理想情况下,如果可以使用wildcard
for 会很好,schoolId
但我认为这是不可能的。
我可以返回键集值并对其进行迭代以仅在上找到匹配项,lastname
但我认为这样做的效果不是很好-请告诉我您是否不同意,或者这是否是实现此目标的最佳方法?还是我应该以其他方式实施?
试试这个。它流式传输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] 删除。
我来说两句