2017-07-30 6 views
5

है दो वर्गों और दो संगत सूचियां:जावा 8 धाराओं: एक सूची है कि एक और सूची से मूल्यों के आधार पर गणना की स्थिति से मेल से आइटम खोजने के

class Click { 
    long campaignId; 
    Date date; 
} 

class Campaign { 
    long campaignId; 
    Date start; 
    Date end; 
    String type; 
} 

List<Click> clicks = ..; 
List<Campaign> campaigns = ..; 

और clicks कि सभी Click रों लगाना चाहते हैं:

  1. एक इसी Campaigncampaigns में सूची, यानी, एक ही campaignId और

  2. साथ Campaign है
  3. यह Campaigntype है = "भावी" और

  4. यह Campaigns.start < click.date < Campaigns.end

अब तक मेरे पास है निम्नलिखित कार्यान्वयन (जो मेरे लिए भ्रामक और जटिल लगता है):

clicks. 
     stream(). 
     filter(click -> campaigns.stream().anyMatch(
       campaign -> campaign.getCampaignType().equals("prospecting") && 
         campaign.getCampaignId().equals(click.getCampaignId()) && 
         campaign.getStart().after(click.getDate()) && 
         campaign.getEnd().before(click.getDate()))). 
     collect(toList()); 

मुझे आश्चर्य है कि समस्या के लिए सरल समाधान है या नहीं।

+8

प्रयास करें। –

+0

@ जोएसी क्या यह वास्तव में संभव है? यह लैम्ब्डा दोनों क्लिक और अभियान को संदर्भित करता है जिसका अर्थ है कि फ़िल्टर को स्वीकार करते समय मुझे बायप्र्रेडिकेट का उपयोग करने की आवश्यकता होगी –

+5

'क्लिक करें -> चेक कैंपेन (क्लिक, अभियान) ' –

उत्तर

1
public List<Click> findMatchingClicks(List<Campaign> cmps, List<Click> clicks) { 
    List<Campaign> cmpsProspective = cmps.stream().filter(cmp -> "prospective".equals(cmp.type)).collect(Collectors.toList()); 
    return clicks.stream().filter(c -> matchesAnyCmp(c, cmpsProspective).collect(Collectors.toList()); 
} 

public boolean matchesAnyCmp(Click click, List<Campaign> cmps) { 
    return cmps.stream().anyMatch(click -> cmp.start.before(click.date) && cmp.end.after(click.date)); 
} 

गेटर्स के लिए फ़ील्ड को बदलें, बस इसे तुरंत लिखा।

1

एक चीज जो खड़ी है वह यह है कि आपकी दूसरी आवश्यकता के मिलान के साथ कुछ लेना देना नहीं है, यह केवल campaigns पर एक शर्त है। अगर यह किसी भी आपके लिए बेहतर है आप परीक्षण करने के लिए होगा:

clicks.stream() 
    .filter(click -> campaigns.stream() 
     .filter(camp -> "prospecting".equals(camp.type)) 
     .anyMatch(camp -> 
      camp.campaignId == click.campaignId && 
      camp.end.after(click.date) && 
      camp.start.before(click.date) 
     ) 
    ) 
    .collect(Collectors.toList()); 

अन्यथा, मैं कभी नहीं एक धाराओं समाधान है जो कि 1 की विधेय के अंदर 2 संग्रह स्ट्रीमिंग शामिल नहीं करता है देखा है, तो आप नहीं कर सकते आपने जो किया उससे ज्यादा बेहतर करें। पठनीयता के संदर्भ में, अगर यह है कि भ्रामक लगता है कि आप तो एक तरीका है कि बूलियन हालत के लिए परीक्षण बना सकते हैं और इसे कहते हैं:

clicks.stream() 
    .filter(click -> campaigns.stream() 
     .filter(camp -> "pre".equals(camp.type)) 
     .anyMatch(camp -> accept(camp, click)) 
    ) 
    .collect(Collectors.toList()); 

static boolean accept(Campaign camp, Click click) { 
    return camp.campaignId == click.campaignId && 
      camp.end.after(click.date) && 
      camp.start.before(click.date); 
} 

अंत में, 2 असंबंधित सुझाव:

  1. का उपयोग न करें पुराना Date वर्ग, इसके बजाय नए java.time API के LocalDate का उपयोग करें।
  2. तो Campaign के type केवल कुछ पूर्वनिर्धारित मान हो सकते हैं (जैसे "प्रस्तुत", "पूर्वेक्षण", "स्वीकार किए जाते हैं" ...) तो एक enum एक सामान्य String तुलना में एक बेहतर फिट होगा।
1

ठीक है, आपकी समस्या आईएमओ को हल करने का एक बहुत ही साफ तरीका है, होल्गर से आने वाला मूल विचार (मुझे प्रश्न मिल जाएगा और इसे यहां लिंक करें)।

आप कि चेक करता है अपने विधि निर्धारित कर सकते हैं (मैं इसे आसान बना दिया है सिर्फ एक बिट):

static boolean checkClick(List<Campaign> campaigns, Click click) { 
    return campaigns.stream().anyMatch(camp -> camp.getCampaignId() 
       == click.getCampaignId()); 
} 

और एक समारोह है कि मानकों को बांधता है परिभाषित:

public static <T, U> Predicate<U> bind(BiFunction<T, U, Boolean> f, T t) { 
    return u -> f.apply(t, u); 
} 

और उपयोग होगा:

BiFunction<List<Campaign>, Click, Boolean> biFunction = YourClass::checkClick; 
Predicate<Click> predicate = bind(biFunction, campaigns); 

clicks.stream() 
     .filter(predicate::test) 
     .collect(Collectors.toList()); 
+1

यह वास्तव में साफ है, लेकिन ओपी ने कहा कि उन्हें अपना वर्तमान समाधान "भ्रमित और जटिल" लगता है, इसलिए मैं कल्पना नहीं कर सकता कि यह कम है। – user1803551

3

मेरे 2 सेंट: चूंकि कोई ज्यादा बॉयलरप्लेट कोड है ओपी में तो कोड में लाइनों/अक्षरों को कम करने के लिए यह संभव/आवश्यक नहीं हो सकता है। हम इसे थोड़ा और स्पष्ट रूप से बनाने के लिए इसे फिर से लिख सकते हैं:

Map<Long, List<Campaign>> map = campaigns.stream().filter(c -> c.type.equals("prospecting")) 
             .collect(Collectors.groupingBy(c -> c.campaignId)); 

clicks.stream().filter(k -> map.containsKey(k.campaignId)) 
       .filter(k -> map.get(k.campaignId).stream().anyMatch(c -> c.start.before(k.date) && c.end.after(k.date))) 
       .collect(Collectors.toList()); 

कोड मूल कोड से बहुत छोटा नहीं है। लेकिन यह टिप्पणियों में उल्लिखित @ मार्को 13 के रूप में ओ (एनएम) से ओ (एन + एम) के प्रदर्शन में सुधार करेगा। यदि आप कम करना चाहते हैं, मैं सब तुम सच में करने के लिए एक नामित विधि में है कि बड़े लैम्ब्डा निकालने की जरूरत है लगता है StreamEx

Map<Long, List<Campaign>> map = StreamEx.of(campaigns) 
       .filter(c -> c.type.equals("prospecting")).groupingBy(c -> c.campaignId); 

StreamEx.of(clicks).filter(k -> map.containsKey(k.campaignId)) 
     .filter(k -> map.get(k.campaignId).stream().anyMatch(c -> c.start.after(k.date) && c.end.before(k.date))) 
     .toList(); 
संबंधित मुद्दे