我们有一个看起来像"递归的对象"数据结构。
假设我们有一个Person对象,其结构类似于
public class Person {
private String id;
private Map<String,Person> persons;
public Person(String id, Map<String,Person> persons){
this.id = id;
this.persons = persons;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Map<String, Person> getPersons() {
return persons;
}
public void setPersons(Map<String, Person> persons) {
this.persons = persons;
}
@Override
public String toString() {
return "Person [id=" + id + ", persons=" + persons + "]";
}
}
此对象的示例表示形式为:(样本数据)
Person p1 = new Person("Jim", ImmutableMap.of("A001",new Person("Mike",ImmutableMap.of("D001",new Person("Jack",ImmutableMap.of("E001",new Person("Kim",null))))),
"Z001",new Person("Adam",ImmutableMap.of("Y001",new Person("Eve",ImmutableMap.of("X001",new Person("Dave",null)))))));
注1:ImmutableMap
来自google guava collection
注意2:让我们假设&#39;键&#39;对象中Person的对象是该人的姓名。
根据此人的姓名,迭代和获取ID的最有效方法是什么。?
例如,如果输入是&#39; Eve&#39;,输出应该是&#39; Y001&#39;
答案 0 :(得分:2)
由于您已经在使用Guava,请考虑向Person
类添加这样的方法:
public FluentIterable<Map.Entry<String, Person>> tree() {
if (persons == null)
return FluentIterable.from(ImmutableList.of());
return FluentIterable.from(persons.entrySet())
.transformAndConcat(
entry -> Iterables.concat(ImmutableList.of(entry), entry.getValue().tree()));
}
或者如果你不能使用Java-8:
public FluentIterable<Map.Entry<String, Person>> tree() {
if (persons == null)
return FluentIterable.from(ImmutableList.of());
return FluentIterable.from(persons.entrySet())
.transformAndConcat(
new Function<Entry<String, Person>, Iterable<Entry<String, Person>>>() {
@Override
public Iterable<Map.Entry<String, Person>> apply(
Map.Entry<String, Person> entry) {
return Iterables.concat(ImmutableList.of(entry), entry.getValue().tree());
}
});
}
它会将所有人的树拼成单Iterable
,这可以很容易地用于for循环:
String name = "Eve";
for(Map.Entry<String, Person> e : p1.tree()) {
if(e.getValue().getId().equals(name)) {
System.out.println(e.getKey());
break;
}
}
或使用FluentIterable
操作:
System.out.println(p1.tree()
.firstMatch(e -> e.getValue().getId().equals(name))
.get().getKey());
答案 1 :(得分:2)
对于番石榴TreeTraverser
来说,这是一个完美的工作:
Iterable<Person> allPersons = new TreeTraverser<Person>() {
@Override public Iterable<Person> children(Person p) {
return p.getPersons().values();
}
}.preOrderTraversal(rootPerson);
for (Person p : allPersons) {
if (p.getId().equals(id)) {
return p;
}
}
答案 2 :(得分:0)
您的结构实际上是一种树。所以你可以使用标准的树木排序方法。如果您的树是二叉树(看起来不是这样),您可以非常有效地实现这一目标。
以下内容可行,但我没有证据证明这是最有效的方法。非二进制树大多只需要插入。
效率取决于您认为递归的叠加程度。如果你认为大多数结构都像样本结构,那就是:非常深,但每个级别只有几个人,这将是非常有效的。特别是如果你的结果将接近底部。
public String iterate(String name) {
if (persons != null) {
for (Entry<String, Person> entry : persons.entrySet()) {
Person value = entry.getValue();
if (value.getId().equals(name)) {
return entry.getKey(); //Since the key of each map is the ID when they return the key
} else {
String ans = value.iterate(name);
if (ans != null) {
return ans;
}
}
}
}
return null;
}
它可以快速浏览整个人员列表,而无需返回顶部。
但是,如果你有一个广泛的设置,并且你认为你的价值观大部分都接近顶部,你可以使用类似下面的内容。
public String iterate(String name) {
if (persons != null) {
for (Entry<String, Person> entry : persons.entrySet()) {
Person value = entry.getValue();
if (value.getId().equals(name)) {
return entry.getKey(); //Since the key of each map is the ID when they return the key
}
}
for (Entry<String, Person> entry : persons.entrySet()) {
String ans = entry.getValue().iterate(name);
if (ans != null) {
return ans;
}
}
}
return null;
}
这样可以快速找到结构顶部附近的东西,但在结构底部找到一个人会比较慢。
我猜你会想要上层解决方案,它更标准。但是,我不认为它们之间存在巨大差异。有关它的另一个版本,请参阅this question有关遍历树的信息。