कैसे एक ArrayList या स्ट्रिंग सरणी से सभी अशक्त तत्वों को हटाने के लिए?


188

मैं उस तरह एक पाश के साथ कोशिश करते हैं

// ArrayList tourists

for (Tourist t : tourists) {
    if (t != null) {     
        t.setId(idForm); 
    }   
}

लेकिन यह अच्छा नहीं है। क्या कोई मुझे बेहतर समाधान सुझा सकता है?


बेहतर निर्णय लेने के लिए कुछ उपयोगी बेंचमार्क:

जबकि लूप, फॉर लूप और इटरेटर परफॉर्मेंस टेस्ट


2
उपयोग Iterator? खोदा जावा-डॉक। download.oracle.com/javase/6/docs/api/java/util/…
निशांत

जवाबों:


365

प्रयत्न:

tourists.removeAll(Collections.singleton(null));

जावा एपीआई पढ़ें । कोड java.lang.UnsupportedOperationExceptionअपरिवर्तनीय सूचियों के लिए फेंक देगा (जैसे कि बनाया गया Arrays.asList); देखने के इस उत्तर अधिक जानकारी के लिए।


9
के समय जटिलता List.removeAll()है n ^ 2 । बस केह रहा हू।
हेमंत

8
Java 8 या उसके बाद के लिए, नीचे दिए गए @ MarcG का जवाब देखें।
एंडी थॉमस

2
@ हेमंथ क्या आप उस समय की जटिलता के बारे में विस्तार से बता सकते हैं? क्योंकि यह O(n)मुझे ArrayListऔर दोनों के लिए काफी लग रहा है LinkedList
हेल्डर परेरा

1
@ हेलडरपाइरा मुझे नहीं लगता कि यह इस मामले के लिए होना चाहिए , क्योंकि स्रोत (लाइन 349) दोनों सूचियों के माध्यम से लूप लगता है ( contains()पूरे सरणी को लूप करता है ) और चूंकि singletonकेवल एक ही तत्व है N * 1 = N। हालांकि आम तौर पर यह होगा N^2
मोइरा

6
@ हेमन्थ यह नहीं है। यह n * m है जहाँ m इस मामले में तत्वों की संख्या है null का एक सिंगलटन जो 1. है। यह O (n) है। आप स्रोत कोड को यहां देख सकते हैं और यह देख सकते हैं कि सूची में एक बार पढ़ने और लिखने के लिए, तत्वों को हटाकर एक को हटा दिया जाए।
तांत्रिक करें

117

2015 तक, यह सबसे अच्छा तरीका है (जावा 8):

tourists.removeIf(Objects::isNull);

नोट: यह कोड java.lang.UnsupportedOperationExceptionअचल सूचियों सहित निश्चित आकार की सूचियों (जैसे Arrays.asList के साथ बनाया गया) के लिए फेंक देगा ।


1
“बेस्ट इन द वे? क्या यह अन्य दृष्टिकोणों से तेज है? या यह केवल संक्षिप्तता के आधार पर अधिक पठनीय है?
एंडी थॉमस

15
न केवल संक्षिप्तता के कारण, बल्कि इसलिए कि यह अधिक अभिव्यंजक है। आप इसे लगभग पढ़ सकते हैं: "पर्यटकों से, यदि वस्तु अशक्त है तो हटा दें"। इसके अलावा, पुराना तरीका एक एकल अशक्त वस्तु के साथ एक नया संग्रह बना रहा है, और फिर एक संग्रह की सामग्री को दूसरे से निकालने के लिए कह रहा है। एक हैक का एक सा लगता है, आपको नहीं लगता? गति के बारे में, आपके पास एक बिंदु है, यदि सूची वास्तव में बड़ी है और प्रदर्शन एक चिंता का विषय है, तो मैं दोनों तरीकों का परीक्षण करने का सुझाव दूंगा। मेरा अनुमान है कि removeIfयह तेज़ होगा, लेकिन यह एक अनुमान है।
मार्कज

1
Arrays.asListअपरिवर्तनीय नहीं है । यह निश्चित आकार का है।
पगड़ी उतारकर

@ टर्बनॉफ हाँ, आप सही हैं, बिल्कुल। यह केवल निश्चित आकार का है, मैं उत्तर को अपडेट करूंगा।
मार्क

46
list.removeAll(Collections.singleton(null));

यदि आप इसे Arrays.asList पर उपयोग करते हैं तो यह UnsupportedException को फेंक देगा क्योंकि यह आपको अपरिवर्तनीय प्रतिलिपि देता है इसलिए इसे संशोधित नहीं किया जा सकता है। कोड के नीचे देखें। यह म्यूटेबल कॉपी बनाता है और कोई अपवाद नहीं फेंकेगा

public static String[] clean(final String[] v) {
    List<String> list = new ArrayList<String>(Arrays.asList(v));
    list.removeAll(Collections.singleton(null));
    return list.toArray(new String[list.size()]);
}

18

कुशल नहीं, लेकिन संक्षिप्त है

while(tourists.remove(null));

1
दुर्भाग्य से, आपका समाधान केवल एक ही था जिसने मेरे लिए काम किया ... धन्यवाद!
Pkmmte

सरल और तेज़

5
@ तेज, वास्तव में इसके विपरीत। यदि आपके पास एक बड़ी सूची है तो भयानक धीमी गति से।
गवूरे

18

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

ImmutableList.copyOf(Iterables.filter(tourists, Predicates.notNull()))

7
 for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

यह तब और उपयोगी हो सकता है जब आपको ट्रैवर्स करते समय तत्वों को हटाना पड़े। संयोग है कि मैं तत्वों का उपयोग करने की कोशिश कर रहा था removeAll(..null..)। धन्यवाद!
मुस्तफा

आप मानों को शून्य करने के लिए अंत में हटाने से बेहतर हो सकते हैं। निष्कासन में बैचअरोव, सूची को एक पढ़ने और लिखने के स्थान के साथ स्थानांतरित करता है और सूची को एक बार पुन: प्रसारित करता है, रीड को घुमाता है, लेकिन यह नहीं लिखता है जब यह एक अशक्त हिट करता है। .remove () वैध को पूरे सरणी को हर बार जब भी बुलाया जाता है, तो उसे रोकना पड़ सकता है।
तातारजीत

4

पूर्व जावा 8 आप का उपयोग करना चाहिए:

tourists.removeAll(Collections.singleton(null));

पोस्ट-जावा 8 का उपयोग करें:

tourists.removeIf(Objects::isNull);

यहाँ कारण समय जटिलता है। सरणियों के साथ समस्या यह है कि हटाने का ऑपरेशन पूरा होने में O (n) समय ले सकता है। वास्तव में जावा में यह खाली जगह को बदलने के लिए शेष तत्वों की एक सरणी प्रतिलिपि है। यहां दिए गए कई अन्य समाधान इस मुद्दे को ट्रिगर करेंगे। पूर्व तकनीकी रूप से O (n * m) है जहाँ m 1 है क्योंकि यह एक सिंगलटन नल है: इसलिए O (n)

आपको सिंगलटन को हटा देना चाहिए, आंतरिक रूप से यह एक बैचमूव () करता है जिसमें एक पठन स्थिति और एक लेखन स्थिति होती है। और सूची को प्रसारित करता है। जब यह एक अशक्त हिट करता है, तो यह केवल पढ़ने की स्थिति को 1 से पुनरावृत्त करता है। जब वे समान होते हैं तो वे गुजरते हैं, जब वे भिन्न होते हैं तो यह मूल्यों की नकल के साथ आगे बढ़ता रहता है। फिर अंत में इसका आकार छोटा हो जाता है।

यह आंतरिक रूप से प्रभावी रूप से करता है:

public static <E> void removeNulls(ArrayList<E> list) {
    int size = list.size();
    int read = 0;
    int write = 0;
    for (; read < size; read++) {
        E element = list.get(read);
        if (element == null) continue;
        if (read != write) list.set(write, element);
        write++;
    }
    if (write != size) {
        list.subList(write, size).clear();
    }
}

जिसे आप स्पष्ट रूप से O (n) ऑपरेशन देख सकते हैं।

केवल एक चीज जो कभी भी तेज हो सकती है, यदि आपने सूची को दोनों छोरों से पुनरावृत्त किया है, और जब आपको एक अशक्त पाया गया, तो आप इसके मूल्य को अंत में मिले मूल्य के बराबर सेट करते हैं, और उस मूल्य को घटा देते हैं। और दो मूल्यों के मिलान होने तक इसकी पुनरावृत्ति हुई। आप ऑर्डर को गड़बड़ कर देंगे, लेकिन आपके द्वारा सेट किए गए मानों की संख्या को बहुत कम कर देंगे। यह जानने के लिए एक अच्छा तरीका है, लेकिन यहाँ से बहुत मदद नहीं मिलेगी। () मूल रूप से मुफ़्त है, लेकिन डिलीट का वह रूप आपके बेल्ट के लिए एक उपयोगी उपकरण है।


for (Iterator<Tourist> itr = tourists.iterator(); itr.hasNext();) {
      if (itr.next() == null) { itr.remove(); }
 }

हालांकि यह उचित रूप से उचित लगता है,। इटरेटर पर (।) आंतरिक रूप से कॉल करता है:

ArrayList.this.remove(lastRet);

जो फिर से हटाने के भीतर ओ (एन) ऑपरेशन है। यह एक System.arraycopy () करता है जो फिर से वह नहीं है जो आप चाहते हैं, यदि आप गति की परवाह करते हैं। यह इसे n ^ 2 बनाता है।

वहाँ भी:

while(tourists.remove(null));

जो O (m * n ^ 2) है। यहां हम न केवल सूची को पुनरावृत्त करते हैं। हम पूरी सूची को दोहराते हैं, हर बार जब हम शून्य से मेल खाते हैं। फिर हम निकाले जाने के लिए System.arraycopy () करने के लिए n / 2 (औसत) ऑपरेशन करते हैं। आप काफी शाब्दिक रूप से, मूल्यों के साथ पूरे संग्रह को क्रमबद्ध कर सकते हैं और शून्य मान के साथ आइटम और कम समय में समाप्त ट्रिम कर सकते हैं। वास्तव में, यह सभी टूटे हुए लोगों के लिए सच है। कम से कम सिद्धांत में, वास्तविक system.arraycopy वास्तव में एक एन ऑपरेशन नहीं है। सिद्धांत रूप में, सिद्धांत और व्यवहार एक ही चीज हैं; व्यवहार में वे नहीं हैं।


3

वहाँ से सभी nullमानों को हटाने का एक आसान तरीका है collection। आपको एक संग्रह को पास करना होगा जिसमें removeAll()विधि के लिए एक पैरामीटर के रूप में अशक्त होना चाहिए

List s1=new ArrayList();
s1.add(null);

yourCollection.removeAll(s1);

यह मेरे लिए सबसे अच्छा काम किया। यह आपको अपने "फ़िल्टर एरे" में एक से अधिक प्रविष्टि को आसानी से जोड़ने की अनुमति देता है जो मूल संग्रह के निष्कासन विधि में पारित हो जाता है।

3

Objectsवर्ग एक है nonNull Predicateकि के साथ इस्तेमाल किया जा सकता filter

उदाहरण के लिए:

tourists.stream().filter(Objects::nonNull).collect(Collectors.toList());

1
ढेर अतिप्रवाह में आपका स्वागत है। प्रश्नों का उत्तर देते समय, कृपया अपने कोड की व्याख्या जोड़ने का प्रयास करें। कृपया वापस जाएं और अधिक जानकारी शामिल करने के लिए अपने उत्तर को संपादित करें।
टायलर

3

Java 8 का उपयोग करके, आप यह प्रयोग कर सकते हैं stream()औरfilter()

tourists = tourists.stream().filter(t -> t != null).collect(Collectors.toList())

या

tourists = tourists.stream().filter(Objects::nonNull).collect(Collectors.toList())

अधिक जानकारी के लिए: जावा 8 - स्ट्रीम


1
यह समाधान अपरिवर्तनीय प्रतिलिपि के साथ काम कर रहा है अर्थात -> सूची <स्ट्रिंग> सूचीऑफस्ट्रिंग = Arrays.asList ("test1", null, "test"); ..... भी! धन्यवाद
Anurag_BEHS

2

यह सरणीसूची से डिफ़ॉल्ट अशक्त मानों को हटाने का आसान तरीका है

     tourists.removeAll(Arrays.asList(null));  

अन्यथा स्ट्रिंग मूल्य "अशक्त" सरणी सूची से हटा दें

       tourists.removeAll(Arrays.asList("null"));  

1

मैं इस के साथ चारों ओर खेला और पता चला कि trimToSize () काम करने लगता है। मैं एंड्रॉइड प्लेटफॉर्म पर काम कर रहा हूं इसलिए यह अलग हो सकता है।


2
जावाडॉक के अनुसार, trimToSizeए की सामग्री को संशोधित नहीं करता है ArrayList। यदि यह एंड्रॉइड में अलग है, तो यह संभवतः एक बग है।
फबीयन

1

हम सभी अशक्त मूल्यों को हटाने के लिए उसी के लिए पुनरावृत्ति का उपयोग कर सकते हैं।

Iterator<Tourist> itr= tourists.iterator();
while(itr.hasNext()){
    if(itr.next() == null){
        itr.remove();
    }
}

1

मैंने एक नई सूची बनाने के लिए स्ट्रीम ऑपरेशन कलेक्ट और एक सहायक विधि के साथ स्ट्रीम इंटरफ़ेस का उपयोग किया ।

tourists.stream().filter(this::isNotNull).collect(Collectors.toList());

private <T> boolean isNotNull(final T item) {
    return  item != null;
}

2
tourists.stream().filter(s -> s != null).collect(Collectors.toList());
1ac0

1

मुख्य रूप से मैं इसका उपयोग कर रहा हूं:

list.removeAll(Collections.singleton(null));

लेकिन जब मैंने जावा 8 सीखा, तो मैंने इसे बदल दिया:

List.removeIf(Objects::isNull);

0

जावा 8 का उपयोग करते हुए इसे विभिन्न तरीकों से धाराओं, समानांतर धाराओं और removeIfविधि का उपयोग करके किया जा सकता है :

List<String> stringList = new ArrayList<>(Arrays.asList(null, "A", "B", null, "C", null));
List<String> listWithoutNulls1 = stringList.stream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList()); //[A,B,C]
List<String> listWithoutNulls2 = stringList.parallelStream()
                .filter(Objects::nonNull)
                .collect(Collectors.toList()); //[A,B,C]
stringList.removeIf(Objects::isNull); //[A,B,C]

समानांतर धारा उपलब्ध प्रोसेसर का उपयोग करेगी और उचित आकार सूचियों के लिए प्रक्रिया को तेज करेगी। धाराओं का उपयोग करने से पहले बेंचमार्क करना हमेशा उचित होता है।


0

@ लिथियम उत्तर के समान लेकिन "लिस्ट में प्रकार अशक्त नहीं हो सकता" त्रुटि नहीं है:

   list.removeAll(Collections.<T>singleton(null));

0
List<String> colors = new ArrayList<>(
Arrays.asList("RED", null, "BLUE", null, "GREEN"));
// using removeIf() + Objects.isNull()
colors.removeIf(Objects::isNull);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.