তালিকা থেকে কোনও উপাদান সরানোর চেষ্টা করার সময় আমি কেন একটি অসমর্থিত অপারেশন এক্সপসেপশন পাই?


476

আমার এই কোডটি রয়েছে:

public static String SelectRandomFromTemplate(String template,int count) {
   String[] split = template.split("|");
   List<String> list=Arrays.asList(split);
   Random r = new Random();
   while( list.size() > count ) {
      list.remove(r.nextInt(list.size()));
   }
   return StringUtils.join(list, ", ");
}

বুঝতে পেরেছি:

06-03 15:05:29.614: ERROR/AndroidRuntime(7737): java.lang.UnsupportedOperationException
06-03 15:05:29.614: ERROR/AndroidRuntime(7737):     at java.util.AbstractList.remove(AbstractList.java:645)

এটি কিভাবে সঠিক উপায় হবে? Java.15


লিঙ্কলিস্ট ব্যবহার করুন।
লোভা চিত্তুমুরি

উত্তর:


1006

আপনার কোড নিয়ে বেশ কয়েকটি সমস্যা:

উপর Arrays.asListএকটি নির্দিষ্ট আকার তালিকা ফেরার

এপিআই থেকে:

Arrays.asList: নির্দিষ্ট অ্যারে দ্বারা ব্যাক করা একটি স্থির-আকারের তালিকা ফেরত দেয় ।

আপনি এটি করতে পারবেন না add; আপনি removeএটি থেকে পারবেন না । আপনি কাঠামোগতভাবে পরিবর্তন করতে পারবেন না List

ফিক্স

একটি তৈরি করুন LinkedList, যা দ্রুত সমর্থন করে remove

List<String> list = new LinkedList<String>(Arrays.asList(split));

উপর splitRegex গ্রহণ

এপিআই থেকে:

String.split(String regex): প্রদত্ত নিয়মিত প্রকাশের ম্যাচের চারপাশে এই স্ট্রিংটি বিভক্ত করে

|একটি রেজেক্স মেটাচার্যাক্টর; আপনি যদি একটি আক্ষরিক উপর বিভক্ত করতে চান |, আপনি অবশ্যই এটি থেকে পালাতে হবে \|, যা জাভা স্ট্রিং আক্ষরিক হিসাবে "\\|"

ফিক্স:

template.split("\\|")

আরও ভাল অ্যালগরিদম উপর

removeএলোমেলো সূচকের সাহায্যে একবারে ফোন করার পরিবর্তে, পরিসীমাটিতে পর্যাপ্ত পরিমাণ এলোমেলো সংখ্যা তৈরি করা ভাল, এবং তারপরে Listএকবারের সাথে যথাযথ সূচকগুলিতে listIterator()কল remove()করা ভাল। কোনও প্রদত্ত পরিসরে র্যান্ডম তবে স্বতন্ত্র সংখ্যাগুলি কীভাবে উত্পন্ন করা যায় সে সম্পর্কে স্ট্যাকওভারফ্লোতে প্রশ্ন রয়েছে questions

এটির সাথে আপনার অ্যালগোরিদমটি হবে O(N)


ধন্যবাদ, আমার কাছে স্ট্রিং <10 এ কেবলমাত্র সীমিত উপাদান রয়েছে তাই অপ্টিমাইজেশনের সমস্যা হবে না।
পেন্টিয়াম

6
@ পেন্টিয়াম: আরও একটি জিনিস: আপনি প্রতিবারের জন্য একটি নতুন উদাহরণ তৈরি করা উচিত নয় Random। এটি একটি staticক্ষেত্র করুন এবং এটি একবার বীজ।
polygenelubricants

6
লিঙ্কডলিস্টটি কি আসলেই দ্রুত? লিংকডলিস্ট এবং অ্যারেলিস্ট উভয়েরই এখানে (ও) অপসারণ রয়েছে: just কেবলমাত্র একটি
অ্যারেলিস্ট

2
লিংকডলিস্ট বনাম অ্যারেলিস্ট -> রায়ান থেকে একটি পারফরম্যান্স পরীক্ষার গ্রাফ রয়েছে। লিংকডলিস্ট অপসারণে দ্রুত।
টর্নো

লিঙ্কডলিস্ট অপসারণের সময় কেবলমাত্র দ্রুতই যখন সরানো নোডটি ইতিমধ্যে জানা যায়। আপনি যদি কোনও উপাদান অপসারণের চেষ্টা করছেন তবে সঠিক উপাদানটি না পাওয়া পর্যন্ত প্রতিটি উপাদানটির সাথে তুলনা করা উচিত, তালিকাটি অবশ্যই সরানো উচিত। আপনি যদি সূচকে অপসারণের চেষ্টা করছেন, অবশ্যই এন ট্র্যাভারসাল করা উচিত। এই ট্র্যাভারসালগুলি অত্যন্ত ব্যয়বহুল, এবং সিপিইউ ক্যাশিংয়ের জন্য সবচেয়ে খারাপ পরিস্থিতি: অনেকগুলি মেমরির আশেপাশে অনাকাঙ্ক্ষিত উপায়ে ঝাঁপিয়ে পড়ে। দেখুন: youtube.com/watch?v=YQs6IC-vgmo
আলেকজান্ডার - মনিকা

143

এই আমাকে বহুবার জ্বালিয়ে দিয়েছে। Arrays.asListএকটি অশোধিত তালিকা তৈরি করে। জাভাডোক থেকে: নির্দিষ্ট অ্যারে দ্বারা ব্যাক করা একটি নির্দিষ্ট আকারের তালিকা ফেরত দেয় ।

একই বিষয়বস্তু সহ একটি নতুন তালিকা তৈরি করুন:

newList.addAll(Arrays.asList(newArray));

এটি কিছুটা অতিরিক্ত আবর্জনা তৈরি করবে তবে আপনি এটিকে পরিবর্তন করতে সক্ষম হবেন।


6
মাইনর পয়েন্ট, তবে আপনি মূল তালিকাটি "মোড়ানো" করছেন না, আপনি সম্পূর্ণ নতুন তালিকা তৈরি করছেন (যার কারণে এটি কাজ করে)।
জ্যাক লেও

হ্যাঁ, আমি আমার জুনিয়ট পরীক্ষার ক্ষেত্রে অ্যারে.এএসলিস্ট () ব্যবহার করেছি, যা আমার মানচিত্রের ভিতরে সংরক্ষণ করা হয়েছিল। তালিকাটি আমার নিজের অ্যারেলিস্টে প্রবেশের অনুলিপি করতে আমার কোড পরিবর্তন করে।
cs94njw

আপনার সমাধানটি আমার পরিস্থিতিতে কাজ করে না, তবে ব্যাখ্যাটির জন্য ধন্যবাদ। আপনার দেওয়া জ্ঞান আমার সমাধানের দিকে নিয়ে যায়।
স্কট বিগস

54

সম্ভবত আপনি অবিচ্ছেদ্য মোড়কের সাথে কাজ করছেন বলে সম্ভবত ।

এই লাইনটি পরিবর্তন করুন:

List<String> list = Arrays.asList(split);

এই লাইনে:

List<String> list = new LinkedList<>(Arrays.asList(split));

5
অ্যারে.এএসলিস্ট () কোনও আপত্তিজনক মোড়ক নয়।
দিমিত্রিস আন্দ্রেউ

@ পলিজেলেনব্রিক্যান্টস: মনে হচ্ছে আপনি মিশ্রিত হয়েছেন unmodifiableএবং immutableunmodifiableএর অর্থ হ'ল "সংশোধনযোগ্য, তবে কাঠামোগতভাবে নয়"।
রোমান

2
আমি কেবল একটি unmodifiableListমোড়ক তৈরি করে চেষ্টা করেছি set; এটা ছোঁড়ার UnsupportedOperationException। আমি বেশ নিশ্চিত Collections.unmodifiable*হ'ল সত্যিকার অর্থে সম্পূর্ণ স্থায়ীত্ব, কেবল কাঠামোগত নয়।
polygenelubricants

1
এই মন্তব্যগুলি 7 বছর পরে পড়া আমি নিজেকে এই লিঙ্কটি ইঙ্গিত করার অনুমতি দিচ্ছি: স্ট্যাকওভারফ্লো / প্রশ্নগুলি / 8892350/… অপরিবর্তনীয় এবং অপরিবর্তনীয়, এখানে আলোচিত মধ্যে পার্থক্য ঠিক করতে পারে।
নাথান রিপার্ট

14

আমি মনে করি যে প্রতিস্থাপন:

List<String> list = Arrays.asList(split);

সঙ্গে

List<String> list = new ArrayList<String>(Arrays.asList(split));

সমস্যা সমাধান করে


5

ফিরিয়ে দেওয়া তালিকাটি Arrays.asList()সম্ভবত অস্থির হতে পারে। আপনি চেষ্টা করতে পারেন

List<String> list = new ArrayList(Arrays.asList(split));

1
তিনি মুছে ফেলছেন, অ্যারেলিস্ট এর মানগুলি মুছে ফেলার জন্য সেরা ডেটা স্ট্রাকচার নয়। লিংকডলিস্ট তার সমস্যার জন্য আরও অনেক কিছু পান।
রোমান

2
লিঙ্কডলিস্ট সম্পর্কিত ভুল। তিনি সূচকে অ্যাক্সেস করছেন, তাই লিঙ্কডলিস্ট পুনরাবৃত্তির মাধ্যমে কোনও উপাদান খুঁজে পেতে যতটা সময় ব্যয় করবে। একটি অ্যারেলিস্ট ব্যবহার করে আরও ভাল পদ্ধতির জন্য আমার উত্তর দেখুন।
দিমিত্রিস আন্দ্রেউ

4

AsList পদ্ধতির জন্য কেবল জাভাডোকটি পড়ুন:

নির্দিষ্ট অ্যারেতে অবজেক্টের একটি {@ কোড কোড} প্রদান করে। {@ কোড কোড} এর আকার পরিবর্তন করা যায় না, অর্থাৎ যোগ করা এবং অপসারণ অসমর্থিত তবে উপাদানগুলি সেট করা যায়। একটি উপাদান সেট করা অন্তর্নিহিত অ্যারে সংশোধন করে।

এটি জাভা 6 থেকে এসেছে তবে দেখে মনে হচ্ছে এটি অ্যান্ড্রয়েড জাভাটির জন্য একই।

সম্পাদনা

ফলাফলের তালিকার ধরণ Arrays.ArrayListযা অ্যারেসক্লাসের ভিতরে একটি প্রাইভেট ক্লাস। ব্যবহারিকভাবে বলতে গেলে, আপনি যে অ্যারেটি দিয়ে গেছেন তা তালিকার দর্শন ছাড়া আর কিছুই নয় Arrays.asList। ফলাফল সহ: আপনি যদি অ্যারে পরিবর্তন করেন তবে তালিকাটিও পরিবর্তিত হবে। এবং যেহেতু একটি অ্যারে পুনরায় আকারযোগ্য নয়, অপসারণ অপসারণ ও অপসারণ করা আবশ্যক


4

অ্যারে.এএসলিস্ট () এমন একটি তালিকা ফেরত দেয় যা তার আকারকে প্রভাবিত করে ক্রিয়াকলাপগুলিকে মঞ্জুরি দেয় না (নোট করুন যে এটি "অবিস্মরণীয়" হিসাবে একই নয়)।

আপনি new ArrayList<String>(Arrays.asList(split));একটি আসল অনুলিপি তৈরি করতে পারেন, তবে আপনি যা করার চেষ্টা করছেন তা দেখে এখানে একটি অতিরিক্ত পরামর্শ দেওয়া হয়েছে (এর O(n^2)ঠিক নীচে আপনার একটি অ্যালগোরিদম রয়েছে)।

আপনি তালিকা থেকে এলোমেলো উপাদানগুলি মুছতে list.size() - count(এটি কল করতে দিন k) চান want কেবলমাত্র অনেকগুলি এলোমেলো উপাদান বেছে নিন এবং সেগুলি তালিকার শেষ kপজিশনে স্যুইপ করুন, তারপরে সেই পুরো ব্যাপ্তিটি মুছুন (যেমন সাবলিস্ট ব্যবহার করে) (এবং এতে পরিষ্কার ())। এটি এটাকে একদম জোঁকের দিকে পরিণত করবে এবং এর অর্থ O(n)অ্যালগরিদম ( O(k)আরও সুনির্দিষ্ট)।

আপডেট : নীচে উল্লিখিত হিসাবে, এই অ্যালগরিদম কেবল তখনই তাৎপর্য লাভ করে যদি উপাদানগুলি আনর্ডারড করা হয়, উদাহরণস্বরূপ যদি তালিকাটি কোনও ব্যাগ উপস্থাপন করে। অন্যদিকে, তালিকার যদি অর্থপূর্ণ অর্ডার থাকে তবে এই অ্যালগরিদম এটি সংরক্ষণ করে না (পরিবর্তে পলিজেনিউব্রিকেন্টস অ্যালগরিদম হবে)।

আপডেট 2 : সুতরাং পূর্ববর্তী ক্ষেত্রে, আরও ভাল (লিনিয়ার, অর্ডার বজায় রাখা, তবে ও (এন) এলোমেলো সংখ্যার সাথে) অ্যালগোরিদমটি এরকম কিছু হবে:

LinkedList<String> elements = ...; //to avoid the slow ArrayList.remove()
int k = elements.size() - count; //elements to select/delete
int remaining = elements.size(); //elements remaining to be iterated
for (Iterator i = elements.iterator(); k > 0 && i.hasNext(); remaining--) {
  i.next();
  if (random.nextInt(remaining) < k) {
     //or (random.nextDouble() < (double)k/remaining)
     i.remove();
     k--;
  }
}

1
অ্যালগরিদমের জন্য +1, যদিও ওপি বলেছে যে কেবলমাত্র 10 টি উপাদান রয়েছে। এবং সাথে এলোমেলো সংখ্যা ব্যবহার করার দুর্দান্ত উপায় ArrayList। আমার পরামর্শের চেয়ে অনেক সহজ। আমি মনে করি এটি এর উপাদানগুলিকে পুনরায় সাজিয়ে তুলবে।
polygenelubricants

4

আমি এই সমস্যার আরেকটি সমাধান পেয়েছি:

List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);

কাজ করা newList;)


2

এই অসমর্থিত অপারেশন এক্সপেকশনটি আসে যখন আপনি সংগ্রহের ক্ষেত্রে কিছু অপারেশন করার চেষ্টা করেন যেখানে এটি অনুমোদিত নয় এবং আপনার ক্ষেত্রে, আপনি যখন কল করবেন তখন Arrays.asListএটি ফিরে আসে না java.util.ArrayList। এটি প্রত্যাবর্তনযোগ্য একটি java.util.Arrays$ArrayListতালিকা যা দেয়। আপনি এটিতে যুক্ত করতে পারবেন না এবং এটি থেকে সরাতে পারবেন না।


2

হ্যাঁ, Arrays.asListস্থির আকারের তালিকাটি ফিরিয়ে দিচ্ছি।

একটি লিঙ্কযুক্ত তালিকা ব্যবহার ব্যতীত, কেবল addAllপদ্ধতি তালিকা ব্যবহার করুন ।

উদাহরণ:

String idList = "123,222,333,444";

List<String> parentRecepeIdList = new ArrayList<String>();

parentRecepeIdList.addAll(Arrays.asList(idList.split(","))); 

parentRecepeIdList.add("555");

2

প্রতিস্থাপন করা

List<String> list=Arrays.asList(split);

প্রতি

List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));

অথবা

List<String> list = new ArrayList<>(Arrays.asList(split));

অথবা

List<String> list = new ArrayList<String>(Arrays.asList(split));

বা (সরান উপাদানগুলির জন্য ভাল)

List<String> list = new LinkedList<>(Arrays.asList(split));

2

অ্যারেলিস্ট সংক্ষিপ্ত তালিকা = অ্যারেএস.এললিস্ট (); // পরিবর্তনযোগ্য অ্যারেলিস্টকে ফেরত দেয় এটিকে পরিবর্তনযোগ্য সমাধান হিসাবে তৈরি করা হবে: অ্যারেলিস্ট ন্যারেলিলিস্ট = নতুন অ্যারেলিস্ট (অ্যারেএস.এললিস্ট ());


1
তাই আপনাকে স্বাগতম। যদিও আমরা আপনার উত্তরের জন্য আপনাকে ধন্যবাদ জানাই, অন্য উত্তরগুলির উপরে যদি এটি অতিরিক্ত মান সরবরাহ করে তবে এটি আরও ভাল। এই ক্ষেত্রে, আপনার উত্তর অতিরিক্ত মান সরবরাহ করে না, যেহেতু অন্য ব্যবহারকারী ইতিমধ্যে সমাধানটি পোস্ট করেছেন। যদি পূর্বের উত্তরটি আপনার পক্ষে সহায়ক ছিল, আপনার যথেষ্ট সুনামের পরে আপনি এটি দিয়েছিলেন।
টেকনোজেক 1995

1

নিম্নলিখিত অ্যারে থেকে কোড স্নিপেট হয়

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

    /**
     * @serial include
     */
    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
        private static final long serialVersionUID = -2764017481108945198L;
        private final E[] a;

সুতরাং যা হয় তা হ'ল আসলিস্ট পদ্ধতিটি যখন ডাকা হয় তখন এটি তার নিজস্ব প্রাইভেট স্ট্যাটিক শ্রেণীর সংস্করণটির তালিকা দেয় যা অ্যারেতে উপাদান সংরক্ষণের জন্য অ্যাবস্ট্রাকলিস্ট থেকে ফানসিওনকে ওভাররাইড করে না। সুতরাং ডিফল্টরূপে বিমূর্ত তালিকার পদ্ধতিটি ব্যতিক্রম ছুঁড়ে।

সুতরাং এটি নিয়মিত অ্যারে তালিকা নয়।


1

আপনি সরাতে পারবেন না, বা অ্যারেগুলির একটি নির্দিষ্ট-আকারের তালিকায় যুক্ত করতে পারবেন না।

তবে আপনি সেই তালিকা থেকে আপনার সাবলিস্ট তৈরি করতে পারেন।

list = list.subList(0, list.size() - (list.size() - count));

public static String SelectRandomFromTemplate(String template, int count) {
   String[] split = template.split("\\|");
   List<String> list = Arrays.asList(split);
   Random r = new Random();
   while( list.size() > count ) {
      list = list.subList(0, list.size() - (list.size() - count));
   }
   return StringUtils.join(list, ", ");
}

* অন্য উপায় হয়

ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));

এটি অ্যারেলিস্ট তৈরি করবে যা অ্যারেএস.এললিস্টের মতো স্থির আকার নয়


0

Arrays.asList() অভ্যন্তরীণভাবে স্থির আকারের অ্যারে ব্যবহার করে।
আপনি এ থেকে গতিশীল যোগ করতে বা সরাতে পারবেন নাArrays.asList()

এটা ব্যবহার কর

Arraylist<String> narraylist=new ArrayList(Arrays.asList());

ইন narraylistআপনি সহজেই Add or Remove আইটেম পারবেন না।


0

একটি নতুন তালিকা তৈরি করা এবং নতুন তালিকায় বৈধ মানগুলি তৈরি করা আমার পক্ষে কাজ করেছে।

কোড নিক্ষেপ ত্রুটি -

List<String> list = new ArrayList<>();
   for (String s: list) {
     if(s is null or blank) {
        list.remove(s);
     }
   }
desiredObject.setValue(list);

ঠিক করার পরে -

 List<String> list = new ArrayList<>();
 List<String> newList= new ArrayList<>();
 for (String s: list) {
   if(s is null or blank) {
      continue;
   }
   newList.add(s);
 }
 desiredObject.setValue(newList);
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.