2017-06-09 25 views
2

我有2个包含多个对象的列表。我想过滤在特定属性中包含相同String值的对象。 我们假设listA包含属性为id的对象。虽然它包含不同的对象,但与listB相同。尽管这两个列表中的一些对象具有相同的ID。我想过滤这些对象并将它们放入新列表中。这是我走到这一步:Java过滤器列表,以便它只包含与另一个列表具有相同属性的对象

List<Customer> Clist = Customer.getAllCustomers(); 
    List<License> Llist = License.getAllLicenses(); 

    Predicate<Customer> customerNotNullPredicate = u -> (u.id != null); 
    Predicate<License> licenseNotNullPredicate = u -> (u.id != null); 

    List<Customer> Clistfiltered1 = Clist.parallelStream().filter(customerNotNullPredicate).collect(Collectors.toList()); 
    List<License> Llistfiltered1 = Llist.parallelStream().filter(licenseNotNullPredicate).collect(Collectors.toList()); 
    Clistfiltered1.retainAll(Llistfiltered1); 
    try { 
     Clistfiltered1.get(0); 
    } catch (Exception e){ 
     System.out.println(e); 
    } 

如果当然,retainAll()不返回任何东西,因为这两个名单只包含了不同类型的对象。我如何尝试在对象的特定属性上使用retainAll()

非常感谢您提前。

+1

你不能。当然,你必须首先找到两个列表都有共同点的id。然后,在第二步中,您可以过滤两个列表。 – AKSW

+0

目前尚不清楚你想要什么。你只是筛选非''null'的ID,这与ID是无关的。那么,期望的结果是什么,“客户”实例列表或“许可证”实例列表?那么,'尝试{Clistfiltered1.get(0); } catch(Exception e){...}'...是你测试list.isEmpty()'的首选方法吗?真的吗? – Holger

+1

@Holger由于这个例子直接来自我正在处理的应用程序,可能是我遗漏了一些信息。非空搜索是因为我有很多数据库条目在这个属性为null(我正在使用预定义的数据库),否则会引发异常。预期的结果是只包含ID在两个列表中匹配的对象的列表。 try,catch块只是为了快速测试,看看我得到了什么错误。我仍然在编码的学习过程中,并且从互联网资源中学习所有东西。对不起,我不熟悉最佳做法。 –

回答

1

,但我会解决这样的问题:

import java.util.ArrayList; 
import java.util.Arrays; 
import java.util.List; 
import java.util.stream.Collectors; 


public class DifferentCollections { 

    public static void main(String[] args) { 


     List<Customer> customers = new ArrayList<>(Arrays.asList(new Customer(1), new Customer(2), new Customer(10))); 
     List<License> licenses = new ArrayList<>(Arrays.asList(new License(1), new License(2), new License(30))); 

     List<Customer> filteredCustomers = customers.stream(). 
       filter(c -> customerIdFoundInLicensesList(c, licenses)). 
       collect(Collectors.toList()); 

     System.out.println(filteredCustomers); 
    } 

    private static boolean customerIdFoundInLicensesList(Customer customer, List<License> licenses) { 
     return licenses.stream(). 
       filter(l -> l.getId().equals(customer.getId())). 
       findAny(). 
       isPresent(); 
    } 
} 

class Customer { 
    Integer id; 

    public Customer(Integer id) { 
     this.id = id; 
    } 

    public Integer getId() { 
     return id; 
    } 

    @Override 
    public String toString() { 
     return "Customer{" + "id=" + id + '}'; 
    } 
} 

class License { 
    Integer id; 

    public License(Integer id) { 
     this.id = id; 
    } 

    public Integer getId() { 
     return id; 
    } 

    @Override 
    public String toString() { 
     return "License{" + "id=" + id + '}'; 
    } 
} 
+0

当你需要的是一个List时,没有理由将'Arrays.asList'返回的'List'复制到'ArrayList'中。此外,'filter(condition).findAny()。isPresent()'可以简化为'.anyMatch(condition)'。 – Holger

+0

也不需要遍历每个客户的许可证列表。 –

0

您不能在两种不同类型(客户和许可证)之间进行retainAll操作。我建议你找只在两个集合ID,然后只要你想

List<Long> customerIds = Clist.map(Customer::id).filter(Objects::notNull); 
List<Long> licenseIds = Llist.map(Customer::id).filter(Objects::notNull); 
List<Long> sharedIds = cusomerIds 
    .stream() 
    .filter(customerId -> licenseIds.contains(customerId)) 
    .collect(Collectors.toList()); 

很明显,不知道该ID在你的情况是长期使用它们,但它应该为所有类型的工作。

在这种情况下,你不能使用中的retainAll()
2

你的任务描述不明确,但显然,要获得所有Customer例如,为此存在具有相同idLicense实例。

尽管可以将其描述为一个流操作,但为另一个列表的每个元素在一个列表中搜索匹配将意味着时间复杂度的操作,换句话说,如果您的操作非常糟糕有很大的名单。

因此,最好有O(n+m)时间复杂度做两个操作:

List<Customer> cList = Customer.getAllCustomers(); 
List<License> lList = License.getAllLicenses(); 

Set<?> licenseIDs = lList.stream() 
    .map(l -> l.id).filter(Objects::nonNull) 
    .collect(Collectors.toSet()); 

List<Customer> cListFiltered = cList.stream() 
    .filter(c -> licenseIDs.contains(c.id)) 
    .collect(Collectors.toList()); 

if(cListFiltered.isEmpty()) System.out.println("no matches"); 
else cListFiltered.forEach(System.out::println); 

虽然通过collect(Collectors.toSet())返回的确切Set类型是不确定的,你可以期望它有一个比线性查找,更好地这允许在后续流操作中使用其方法contains。请注意,只有第一个操作具有用于null值的筛选器;因为这保证licenseIDs集合不包含null,所以具有null id的客户将被隐式拒绝。

这很容易让普通ID,而不是

Set<?> commonIDs = cList.stream() 
    .map(l -> l.id).filter(licenseIDs::contains) 
    .collect(Collectors.toSet()); 

使用commonIDs,您可以同时过滤掉,客户或名单许可证列表,如果你想。

+0

作为一个注意事项,你不应该在每个地方都急切地使用'parallelStream()'。并非所有东西都从并行处理中受益使用不当可能会降低性能。 – Holger

+0

尽管您在理解我的问题时遇到了问题,但我必须感谢您的帮助,欣赏了很多Holger。在使用列表和数据流时,我已经想到了一个非常糟糕的表现,但在这种情况下,这并不重要,因为只有一次执行此函数才能生成数据库条目。但是,在我的应用程序中,我有更多的List流式传输,性能较差,是否使用集合最好? –

+1

这取决于实际操作。流是线性操作,所以如果直接采集操作比线性性能更好(比如Set查找),则应该更喜欢这种操作,特别是当操作将与另一个线性(或更差)操作组合时。 – Holger

相关问题