2017-06-09 28 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

相關問題