【问题标题】:Removing elements from list based on condition根据条件从列表中删除元素
【发布时间】:2017-08-31 11:54:48
【问题描述】:

我有一个代码可以选择性地将数据添加到如下地图中,

public static void main(String[] args) {

        List<Person> people = Arrays.asList(
                new Person("Johnny", "Depp", 18),
                new Person("Jennifer", null, 30),
                new Person("Angelina", null, 23),
                new Person("Angelina", "Garlic", 38),
                new Person("Angelina", "Jolie", 40),
        );

        Map<String, Person> map = new HashMap<>();

        for (Person person:
             people) {
            Person temp = map.get(person.getFirstName());
            if(temp == null || temp.getLastName() == null)
                map.put(person.getFirstName(), person);
        }

        for (Map.Entry mapper:
             map.entrySet()) {
            Person temp = (Person) mapper.getValue();
            System.out.println(temp.getFirstName());
            System.out.println(temp.getLastName());
            System.out.println();
        }

    }

Person.java 包含以下内容:

public class Person {

    String firstName;
    String lastName;
    int age;

    public Person(String firstName, String lastName, int age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public int getAge() {
        return age;
    }

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

现在,我需要检查以下条件, 1) 是地图有多条同名的记录;如果记录的姓氏为空,则应将此记录添加到地图中。 2) 如果地图中只有一个人的名字记录;如果该记录的姓氏为空,则它有资格添加到地图中。

所以我目前的解决方案得到的输出是,

约翰尼 德普

詹妮弗 空

安吉丽娜 大蒜

我需要的输出应该在哪里,

约翰尼 德普

詹妮弗 空

安吉丽娜 大蒜

安吉丽娜 朱莉

注意:我正在使用 Java 7(不,Java 8 不是一个选项)

【问题讨论】:

  • 我想你的意思是,如果有多个记录的名字相同而一个姓氏为空,那么它应该添加吗?
  • 我不明白这个问题的标题。它与根据条件从列表中删除元素有什么关系?

标签: java algorithm arraylist hashmap filtering


【解决方案1】:

这是因为,在 Map 中,键必须是唯一的,因此当您第二次检查 Angelina 时,它匹配,因为姓氏是 null,并且您放入地图时会覆盖原来的 Angelina。 Maps 必须有唯一的键,

公共接口地图 将键映射到值的对象。地图不能包含重复的键;每个键最多可以映射到一个值。

我找到了两种不同的解决方法

1.使用补充列表来维护将覆盖当前键的对象

List<Person> supplementaryList = new ArrayList<Person>();

Map<String, Person> map = new HashMap<String, Person>();

for (Person person : people) {

  Person temp = map.get(person.getFirstName());

  if (temp != null) {
    supplementaryList.add(person);
    if (temp.getLastName() == null)
      map.remove(temp.getFirstName());

  } else {
    map.put(person.getFirstName(), person);
  }
}

for (Map.Entry mapper : map.entrySet()) {
  Person temp = (Person) mapper.getValue();
  System.out.println(temp.getFirstName());
  System.out.println(temp.getLastName());
  System.out.println();
}

for (Person p : supplementaryList) {

  System.out.println(p.getFirstName() + p.getLastName());

}

2。与Map&lt;String,List&lt;Person&gt;&gt;

Map<String, List<Person>> namesMap = new HashMap<String, List<Person>>();

for (Person p : people) {

  List<Person> res = namesMap.get(p.getFirstName());

  // if there is not valid list of names for key add new person
  if (res == null) {
    List<Person> newListOfPeople = new ArrayList<Person>();
    newListOfPeople.add(p);
    namesMap.put(p.getFirstName(), newListOfPeople);
  } else {

    if (p.getLastName() != null) {
      res.add(p);
      namesMap.put(p.getFirstName(), res);
      Iterator<Person> iter = res.iterator();
      // remove null from list if it exists
      while (iter.hasNext()) {
        Person person = iter.next();
        if (person.getLastName() == null)
          iter.remove();
      }
    }
  }
}

for (Map.Entry<String, List<Person>> kv : namesMap.entrySet()) {
  if (kv.getValue() != null) {
    for (Person p : kv.getValue())
      System.out.println(p.getFirstName() + " " + p.getLastName());

  }
}

输出

Johnny Depp
Jennifer null
Angelina Garlic
Angelina Jolie

【讨论】:

  • 是的,我之前尝试过这种方法,但发现设计不太优雅,因为它使用了两种数据结构,然后分别循环遍历它们。虽然我想不出任何其他方法,但感谢您的解决方案!投票赞成!
  • @PewDiePie 我用Map&lt;String, List&lt;Person&gt;&gt; 添加了下面提到的方式的实现。感谢您的支持,祝您好运!
【解决方案2】:

HashMap 不允许重复键 (firstName),因此您无法在 Map 中看到 Angelina Jolie。 来自 java HashMap 的文档。

public V put(K key, V值) 将指定的值与此映射中的指定键相关联。如果映射先前包含键的映射,则替换旧值。

所以我向您推荐两种方法来解决您的问题:

  1. 创建一个Map&lt;String,List&lt;Person&gt;&gt;,所以这里的关键是名字,列表是每个必须满足您要求的人。

  2. 使用支持多键的实现,例如 Apache Commons Collections 的 Multimap,或来自 Guava。

【讨论】:

  • 我认为第一种方法再次需要很多条件,特别是在检查地图中是否不存在密钥时,然后创建一个新的数组列表,然后将其添加到与关联的地图中钥匙。虽然,我正在考虑第二种方法,但我以前没有使用过多地图,如果你能对它有所了解(真的会帮助我)。另外,如果您可以建议一种替代方法,并且根本不使用地图
【解决方案3】:

我想我会分两次完成。

在第一遍中,仅将具有非空姓氏的记录放入临时映射中。别介意重复的名字现在会丢失。

在第二遍之前,创建一个结果集合,集合或列表。地图不行。在第二遍中,对于每个姓氏为空的记录,您可以在映射中检查是否存在任何具有相同名字和非空姓氏的记录。现在您知道哪些记录应该进入您的结果。

一组名字真的足够了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2018-10-12
    • 1970-01-01
    • 2021-11-02
    • 2019-01-16
    • 2020-12-13
    相关资源
    最近更新 更多