कस्टम तुलनित्र के साथ ट्रीसेट में एकत्र करने के लिए धाराओं का उपयोग करना


92

जावा 8 में काम करना, मेरे पास TreeSetइस तरह परिभाषित है:

private TreeSet<PositionReport> positionReports = 
        new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp));

PositionReport इस तरह परिभाषित एक साधारण वर्ग है:

public static final class PositionReport implements Cloneable {
    private final long timestamp;
    private final Position position;

    public static PositionReport create(long timestamp, Position position) {
        return new PositionReport(timestamp, position);
    }

    private PositionReport(long timestamp, Position position) {
        this.timestamp = timestamp;
        this.position = position;
    }

    public long getTimestamp() {
        return timestamp;
    }

    public Position getPosition() {
        return position;
    }
}

यह ठीक काम करता है।

अब मैं से प्रविष्टियां निकालना चाहते हैं TreeSet positionReportsजहां timestampकुछ मूल्य से अधिक पुराना है। लेकिन मैं इसे व्यक्त करने के लिए सही जावा 8 सिंटैक्स का पता नहीं लगा सकता।

यह प्रयास वास्तव में संकलन करता है, लेकिन मुझे एक TreeSetअपरिभाषित तुलनित्र के साथ एक नया देता है :

positionReports = positionReports
        .stream()
        .filter(p -> p.timestamp >= oldestKept)
        .collect(Collectors.toCollection(TreeSet::new))

मैं कैसे व्यक्त करूं, कि मैं TreeSetएक तुलनित्र के साथ इकट्ठा करना चाहता हूं Comparator.comparingLong(PositionReport::getTimestamp)?

मैंने कुछ सोचा होगा

positionReports = positionReports
        .stream()
        .filter(p -> p.timestamp >= oldestKept)
        .collect(
            Collectors.toCollection(
                TreeSet::TreeSet(Comparator.comparingLong(PositionReport::getTimestamp))
            )
        );

लेकिन यह विधि संदर्भों के लिए मान्य वाक्यविन्यास संकलन / प्रकट नहीं करता है।

जवाबों:


118

विधि संदर्भ तब होता है जब आपके पास एक विधि (या कंस्ट्रक्टर) होती है जो पहले से ही उस लक्ष्य के आकार को फिट करती है जिसे आप संतुष्ट करने का प्रयास कर रहे हैं। आप इस मामले में एक विधि संदर्भ का उपयोग नहीं कर सकते क्योंकि आपके द्वारा लक्षित आकार वह है Supplierजो कोई तर्क नहीं लेता है और एक संग्रह लौटाता है, लेकिन आपके पास एक TreeSetनिर्माता है जो एक तर्क लेता है, और आपको उस तर्क को निर्दिष्ट करने की आवश्यकता है है। इसलिए आपको कम संक्षिप्त दृष्टिकोण लेना होगा और एक लंबोदर अभिव्यक्ति का उपयोग करना होगा:

TreeSet<Report> toTreeSet(Collection<Report> reports, long timestamp) {
    return reports.stream().filter(report -> report.timestamp() >= timestamp).collect(
        Collectors.toCollection(
            () -> new TreeSet<>(Comparator.comparingLong(Report::timestamp))
        )
    );
}

4
ध्यान देने वाली एक बात यह है कि अगर आपके ट्रीसेट का प्रकार (इस स्थिति में स्थिति रिप्लेसमेंट) तुलनीय है तो आपको तुलनित्र की आवश्यकता नहीं है।
xtrakBandit

35
@XtrakBandit पर फिर से - यदि आपको तुलनित्र (प्राकृतिक छँटाई) निर्दिष्ट करने की आवश्यकता नहीं है - आप इसे बहुत संक्षिप्त कर सकते हैं:.collect(Collectors.toCollection(TreeSet::new));
जोशुआ गोल्डबर्ग

मुझे यह त्रुटि मिली:toCollection in class Collectors cannot be applied to given types
बहादर तसदीम

@BahadirTasdemir कोड काम करता है। सुनिश्चित करें कि आप केवल एक तर्क दे रहे हैं Collectors::toCollection: a Supplierजो रिटर्न देता है a CollectionSupplierएक प्रकार है जिसमें केवल एक सार पद्धति है, जिसका अर्थ है कि यह इस जवाब के रूप में एक लंबोदर अभिव्यक्ति का लक्ष्य हो सकता है। लैम्ब्डा अभिव्यक्ति में कोई तर्क नहीं होना चाहिए (इसलिए खाली तर्क सूची ()) और एक तत्व प्रकार के साथ एक संग्रह लौटाएं जो आपके द्वारा एकत्र किए जा रहे स्ट्रीम के तत्वों से मेल खाता है (इस मामले में TreeSet<PositionReport>)।
गोडजोन

15

यह आसान है बस अगले कोड का उपयोग करें:

    positionReports = positionReports
        .stream()
        .filter(p -> p.timestamp >= oldestKept)
        .collect(
            Collectors.toCollection(()->new TreeSet<>(Comparator.comparingLong(PositionReport::getTimestamp)
)));

9

आप अंत में केवल एक SortedSet में परिवर्तित कर सकते हैं (बशर्ते कि आपको अतिरिक्त प्रतिलिपि का बुरा न लगे)।

positionReports = positionReports
                .stream()
                .filter(p -> p.getTimeStamp() >= oldestKept)
                .collect(Collectors.toSet());

return new TreeSet(positionReports);

7
ऐसा करते समय आपको सावधानी बरतनी चाहिए। आप ऐसा करते समय तत्वों को खो देते हैं। जैसे कि ऊपर पूछे गए प्रश्न में, तत्वों का प्राकृतिक तुलनित्र एक ओपी का उपयोग करने की तुलना में अलग है। इसलिए आप प्रारंभिक रूपांतरण में हैं, क्योंकि यह एक सेट है, यह कुछ तत्वों को खो सकता है, जो अन्य तुलनित्र के पास नहीं हो सकता है (यानी पहला तुलनित्र compareTo() 0 के रूप में वापस आ सकता है जबकि दूसरा कुछ तुलनाओं के लिए नहीं हो सकता है। सभी जहां compareTo()0 है खो दिया है क्योंकि यह एक सेट है।)
looneyGod

6

धाराओं का उपयोग किए बिना इसके लिए संग्रह पर एक विधि है default boolean removeIf(Predicate<? super E> filter):। जावदोक को देखें ।

तो आपका कोड इस तरह दिख सकता है:

positionReports.removeIf(p -> p.timestamp < oldestKept);

1
positionReports = positionReports.stream()
                             .filter(p -> p.getTimeStamp() >= oldestKept)
                             .collect(Collectors.toCollection(() -> new 
TreeSet<PositionReport>(Comparator.comparingLong(PositionReport::getTimestamp))));

0

ट्रीसेट के साथ समस्या यह है कि जिस तुलनित्र को हम वस्तुओं को छांटना चाहते हैं उसका उपयोग सेट में आइटम सम्मिलित करते समय डुप्लिकेट का पता लगाने के लिए भी किया जाता है। इसलिए यदि तुलनित्र फ़ंक्शन दो वस्तुओं के लिए 0 है, तो यह गलत तरीके से इसे डुप्लिकेट के रूप में मानते हुए अस्वीकार कर देता है।

डुप्लिकेट का पता लगाने के लिए मदों की एक अलग सही हैशकोड विधि द्वारा किया जाना चाहिए। मैं सभी गुणों (आईडी और उदाहरण में नाम) पर विचार करते हुए हैशकोड के साथ डुप्लिकेट को रोकने के लिए एक साधारण हैशसेट का उपयोग करना पसंद करता हूं और आइटम प्राप्त करते समय एक साधारण क्रमबद्ध सूची लौटाता हूं (उदाहरण में केवल नाम से छंटनी)

public class ProductAvailableFiltersDTO {

    private Set<FilterItem> category_ids = new HashSet<>();

    public List<FilterItem> getCategory_ids() {
        return category_ids.stream()
            .sorted(Comparator.comparing(FilterItem::getName))
            .collect(Collectors.toList());
    }

    public void setCategory_ids(List<FilterItem> category_ids) {
        this.category_ids.clear();
        if (CollectionUtils.isNotEmpty(category_ids)) {
            this.category_ids.addAll(category_ids);
        }
    }
}


public class FilterItem {
    private String id;
    private String name;

    public FilterItem(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof FilterItem)) return false;
        FilterItem that = (FilterItem) o;
        return Objects.equals(getId(), that.getId()) &&
                Objects.equals(getName(), that.getName());
    }

    @Override
    public int hashCode() {

        return Objects.hash(getId(), getName());
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.