Related
I've created a Hashtable with a String as key and a LinkedList of Strings as my value. Here is my implementation:
Hashtable <String, LinkedList<String>> table = new Hashtable <String, LinkedList<String>>();
What I want to do is sort a file of words and store each sorted word into the hashtable (represents the key) and the store the ORIGINAL word as part of my LinkedList value.
For example, if word is
"cat"
Sorted = "act"
Store in Hashtable (key : act, value : cat);
Now I'm just getting confused how to essentially add to my LinkedList.
This is what I was thinking :
LinkedList <String> temp = table.get(sortedWord) //if null, then nothing in list
if(temp==null)
table.put(sortedWord,temp.add(originalWord));
This is not working since its not following the library functions but I'm unsure of how I would do this.
Here is my solution. The solution is looping through the words, sorting the chars with Array.sort(). Checking if the Hashtable is populated with the sorted word, and from there either created the LinkedList and adding or adding the element to the already created LinkedList. Not sure why you choose LinkedList as your Datastructure.
Hashtable <String, LinkedList<String>> table = new Hashtable <String, LinkedList<String>>();
for(String s : new String[]{"cat","dog","mouse", "cat"})
{
char[] chars = s.toCharArray();
Arrays.sort(chars);
String sorted = new String(chars);
if(table.containsKey(sorted))
{
LinkedList<String> list = table.get(sorted);
list.add(s);
}
else
{
LinkedList<String> list = new LinkedList<String>();
list.add(s);
table.put(sorted, list);
}
}
Which will produce the following Hashtable.
{act=[cat, cat], emosu=[mouse], dgo=[dog]}
Used this question for Sorting the Chars.
Sort a single String in Java
You can do:
if(!table.containsKey(sorted)) {
table.put(new LinkedList<String>())
}
table.get(sorted).add(...)
The problem with this code:
LinkedList <String> temp = table.get(sortedWord) //if null, then nothing in list
if(temp==null)
table.put(sortedWord,temp.add(originalWord));
is that if temp is null, that means you don't have a LinkedList, but your statement is trying to add originalWord to a LinkedList that doesn't exist. If temp is null, then temp.add is guaranteed to get a NullPointerException.
Using temp.add is what you want to do if you do have a LinkedList (and you don't need another table.put when that happens). If you don't have one, you have to create a new LinkedList with one element. Here's one way:
if (temp == null) {
LinkedList<String> newList = new LinkedList<>(Arrays.asList(originalword));
table.put(sortedWord, newList);
} else {
// you have a LinkedList, add the word to it
(Arrays.asList seems to be the simplest way to create a list with just one element. It won't be a LinkedList, though, so you need an extra constructor call to create the LinkedList.)
For lists, we use the Collections.sort(List) method. What if we want to sort a HashSet?
A HashSet does not guarantee any order of its elements. If you need this guarantee, consider using a TreeSet to hold your elements.
However if you just need your elements sorted for this one occurrence, then just temporarily create a List and sort that:
Set<?> yourHashSet = new HashSet<>();
...
List<?> sortedList = new ArrayList<>(yourHashSet);
Collections.sort(sortedList);
Add all your objects to the TreeSet, you will get a sorted Set. Below is a raw example.
HashSet myHashSet = new HashSet();
myHashSet.add(1);
myHashSet.add(23);
myHashSet.add(45);
myHashSet.add(12);
TreeSet myTreeSet = new TreeSet();
myTreeSet.addAll(myHashSet);
System.out.println(myTreeSet); // Prints [1, 12, 23, 45]
Update
You can also use TreeSet's constructor that takes a HashSet as a parameter.
HashSet myHashSet = new HashSet();
myHashSet.add(1);
myHashSet.add(23);
myHashSet.add(45);
myHashSet.add(12);
TreeSet myTreeSet = new TreeSet(myHashSet);
System.out.println(myTreeSet); // Prints [1, 12, 23, 45]
Thanks #mounika for the update.
Java 8 way to sort it would be:
fooHashSet.stream()
.sorted(Comparator.comparing(Foo::getSize)) //comparator - how you want to sort it
.collect(Collectors.toList()); //collector - what you want to collect it to
*Foo::getSize it's an example how to sort the HashSet of YourItem's naturally by size.
*Collectors.toList() is going to collect the result of sorting into a List the you will need to capture it with List<Foo> sortedListOfFoo =
You can use a TreeSet instead.
Use java.util.TreeSet as the actual object. When you iterate over this collection, the values come back in a well-defined order.
If you use java.util.HashSet then the order depends on an internal hash function which is almost certainly not lexicographic (based on content).
Just in-case you don't wanna use a TreeSet you could try this using java stream for concise code.
set = set.stream().sorted().collect(Collectors.toCollection(LinkedHashSet::new));
You can use Java 8 collectors and TreeSet
list.stream().collect(Collectors.toCollection(TreeSet::new))
Based on the answer given by #LazerBanana i will put my own example of a Set sorted by the Id of the Object:
Set<Clazz> yourSet = [...];
yourSet.stream().sorted(new Comparator<Clazz>() {
#Override
public int compare(Clazz o1, Clazz o2) {
return o1.getId().compareTo(o2.getId());
}
}).collect(Collectors.toList()); // Returns the sorted List (using toSet() wont work)
Elements in HashSet can't be sorted. Whenever you put elements into HashSet, it can mess up the ordering of the whole set. It is deliberately designed like that for performance. When you don't care about the order, HashSet will be the most efficient set for frequent insertions and queries.
TreeSet is the alternative that you can use. When you iterate on the tree set, you will get sorted elements automatically.
But it will adjust the tree to try to remain sorted every time you insert an element.
Perhaps, what you are trying to do is to sort just once. In that case, TreeSet is not the most efficient option because it needs to determine the placing of newly added elements all the time. Use TreeSet only when you want to sort often.
If you only need to sort once, use ArrayList. Create a new list and add all the elements then sort it once. If you want to retain only unique elements (remove all duplicates), then put the list into a LinkedHashSet, it will retain the order you have already sorted.
List<Integer> list = new ArrayList<>();
list.add(6);
list.add(4);
list.add(4);
list.add(5);
Collections.sort(list);
Set<Integer> unique = new LinkedHashSet<>(list); // 4 5 6
Now, you've gotten a sorted set if you want it in a list form then convert it into list.
You can use TreeSet as mentioned in other answers.
Here's a little more elaboration on how to use it:
TreeSet<String> ts = new TreeSet<String>();
ts.add("b1");
ts.add("b3");
ts.add("b2");
ts.add("a1");
ts.add("a2");
System.out.println(ts);
for (String s: ts)
System.out.println(s);
Output:
[a1, a2, a3, a4, a5]
a1
a2
b1
b2
b3
In my humble opinion , LazerBanana's answer should be the top rated answer & accepted because all the other answers pointing to java.util.TreeSet ( or first convert to list then call Collections.sort(...) on the converted list ) didn't bothered to ask OP as what kind of objects your HashSet has i.e. if those elements have a predefined natural ordering or not & that is not optional question but a mandatory question.
You just can't go in & start putting your HashSet elements into a TreeSet if element type doesn't already implement Comparable interface or if you are not explicitly passing Comparator to TreeSet constructor.
From TreeSet JavaDoc ,
Constructs a new, empty tree set, sorted according to the natural
ordering of its elements. All elements inserted into the set must
implement the Comparable interface. Furthermore, all such elements
must be mutually comparable: e1.compareTo(e2) must not throw a
ClassCastException for any elements e1 and e2 in the set. If the user
attempts to add an element to the set that violates this constraint
(for example, the user attempts to add a string element to a set whose
elements are integers), the add call will throw a ClassCastException.
That is why only all Java8 stream based answers - where you define your comparator on the spot - only make sense because implementing comparable in POJO becomes optional. Programmer defines comparator as and when needed. Trying to collect into TreeSet without asking this fundamental question is also incorrect ( Ninja's answer). Assuming object types to be String or Integer is also incorrect.
Having said that, other concerns like ,
Sorting Performance
Memory Foot Print ( retaining original set and creating new sorted sets each time sorting is done or wish to sort the set in - place etc etc )
should be the other relevant points too. Just pointing to API shouldn't be only intention.
Since Original set already contains only unique elements & that constraint is also maintained by sorted set so original set needs to be cleared from memory since data is duplicated.
1. Add all set element in list -> al.addAll(s);
2. Sort all the elements in list using -> Collections.sort(al);
public class SortSetProblem {
public static void main(String[] args) {
ArrayList<String> al = new ArrayList();
Set<String> s = new HashSet<>();
s.add("ved");
s.add("prakash");
s.add("sharma");
s.add("apple");
s.add("ved");
s.add("banana");
System.out.println("Before Sorting");
for (String s1 : s) {
System.out.print(" " + s1);
}
System.out.println("After Sorting");
al.addAll(s);
Collections.sort(al);
for (String set : al) {
System.out.print(" " + set);
}
}
}
input - ved prakash sharma apple ved banana
Output - apple banana prakash sharma ved
If you want want the end Collection to be in the form of Set and if you want to define your own natural order rather than that of TreeSet then -
Convert the HashSet into List
Custom sort the List using Comparator
Convert back the List into LinkedHashSet to maintain order
Display the LinkedHashSet
Sample program -
package demo31;
import java.util.*;
public class App26 {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
addElements(set);
List<String> list = new LinkedList<>();
list = convertToList(set);
Collections.sort(list, new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
int flag = s2.length() - s1.length();
if(flag != 0) {
return flag;
} else {
return -s1.compareTo(s2);
}
}
});
Set<String> set2 = new LinkedHashSet<>();
set2 = convertToSet(list);
displayElements(set2);
}
public static void addElements(Set<String> set) {
set.add("Hippopotamus");
set.add("Rhinocerous");
set.add("Zebra");
set.add("Tiger");
set.add("Giraffe");
set.add("Cheetah");
set.add("Wolf");
set.add("Fox");
set.add("Dog");
set.add("Cat");
}
public static List<String> convertToList(Set<String> set) {
List<String> list = new LinkedList<>();
for(String element: set) {
list.add(element);
}
return list;
}
public static Set<String> convertToSet(List<String> list) {
Set<String> set = new LinkedHashSet<>();
for(String element: list) {
set.add(element);
}
return set;
}
public static void displayElements(Set<String> set) {
System.out.println(set);
}
}
Output -
[Hippopotamus, Rhinocerous, Giraffe, Cheetah, Zebra, Tiger, Wolf, Fox, Dog, Cat]
Here the collection has been sorted as -
First - Descending order of String length
Second - Descending order of String alphabetical hierarchy
you can do this in the following ways:
Method 1:
Create a list and store all the hashset values into it
sort the list using Collections.sort()
Store the list back into LinkedHashSet as it preserves the insertion order
Method 2:
Create a treeSet and store all the values into it.
Method 2 is more preferable because the other method consumes lot of time to transfer data back and forth between hashset and list.
We can not decide that the elements of a HashSet would be sorted automatically. But we can sort them by converting into TreeSet or any List like ArrayList or LinkedList etc.
// Create a TreeSet object of class E
TreeSet<E> ts = new TreeSet<E> ();
// Convert your HashSet into TreeSet
ts.addAll(yourHashSet);
System.out.println(ts.toString() + "\t Sorted Automatically");
You can use guava library for the same
Set<String> sortedSet = FluentIterable.from(myHashSet).toSortedSet(new Comparator<String>() {
#Override
public int compare(String s1, String s2) {
// descending order of relevance
//required code
}
});
SortedSet has been added Since java 7
https://docs.oracle.com/javase/8/docs/api/java/util/SortedSet.html
You can wrap it in a TreeSet like this:
Set mySet = new HashSet();
mySet.add(4);
mySet.add(5);
mySet.add(3);
mySet.add(1);
System.out.println("mySet items "+ mySet);
TreeSet treeSet = new TreeSet(mySet);
System.out.println("treeSet items "+ treeSet);
output :
mySet items [1, 3, 4, 5]
treeSet items [1, 3, 4, 5]
Set mySet = new HashSet();
mySet.add("five");
mySet.add("elf");
mySet.add("four");
mySet.add("six");
mySet.add("two");
System.out.println("mySet items "+ mySet);
TreeSet treeSet = new TreeSet(mySet);
System.out.println("treeSet items "+ treeSet);
output:
mySet items [six, four, five, two, elf]
treeSet items [elf, five, four, six, two]
requirement for this method is that the objects of the set/list should be comparable (implement the Comparable interface)
The below is my sample code and its already answered by pointing the code in comments , am still sharing because it contains the complete code
package Collections;
import java.util.*;
public class TestSet {
public static void main(String[] args) {
Set<String> objset = new HashSet<>();
objset.add("test");
objset.add("abc");
objset.add("abc");
objset.add("mas");
objset.add("vas");
Iterator itset = objset.iterator();
while(itset.hasNext())
{
System.out.println(itset.next());
}
TreeSet<String> treeobj = new TreeSet(objset);
System.out.println(treeobj);
}
}
TreeSet treeobj = new TreeSet(objset); here we are invoking the treeset constructor which will call the addAll method to add the objects .
See this below code from the TreeSet class how its mentioned ,
public TreeSet(Collection<? extends E> c) {
this();
addAll(c);
}
Convert HashSet to List then sort it using Collection.sort()
List<String> list = new ArrayList<String>(hset);
Collections.sort(List)
This simple command did the trick for me:
myHashSet.toList.sorted
I used this within a print statement, so if you need to actually persist the ordering, you may need to use TreeSets or other structures proposed on this thread.
Guys i wanna ask about the best way to iterate collection classes ??
private ArrayList<String> no = new ArrayList<String>();
private ArrayList<String> code = new ArrayList<String>();
private ArrayList<String> name = new ArrayList<String>();
private ArrayList<String> colour = new ArrayList<String>();
private ArrayList<String> size = new ArrayList<String>();
// method for finding specific value inside ArrayList, if match then delete that element
void deleteSomeRows(Collection<String> column, String valueToDelete) {
Iterator <String> iterator = column.iterator();
do{
if (iterator.next()==valueToDelete){
iterator.remove();
}
}while(iterator.hasNext());
}
deleteSomeRows(no, "value" );
deleteSomeRows(code, "value" );
deleteSomeRows(name , "value");
deleteSomeRows(colour ,"value" );
deleteSomeRows(size , "value");
THE PROBLEM WITH CODES ABOVE IS THAT IT TAKES AMOUNT OF TIME JUST TO ITERATE EACH OF THOSE CLASSES ? ANY SOLUTION TO MAKE IT FASTER ? pls help if u care :D..
You could simplify your code:
while column.contains(valueToDelete)
{
column.remove(valueToDelete);
}
You're not going to be able to speed up your ArrayList iteration, especially if your list is not sorted. You're stuck at O(n) for this problem. If you sorted it and inserted logic to binary search for the item to remove until it is no longer found, you could speed up access.
This next suggestion isn't directly related to the time it takes, but it will cause you problems.
You should never compare String objects for equality using the == operator. This will cause a comparison of their pointer values.
Use this instead:
if (iterator.next().equals(valueToDelete))
EDIT: The problem here is not the iteration. The problem is removing the elements from the ArrayList. When you remove the first element from an ArrayList, then all subsequent elements have to be shifted one position to the left. So in the worst case, your current approach will have quadratic complexity.
It's difficult to avoid this in general. But in this case, the best tradeoff between simplicity and performance can probably be achieved like this: Instead of removing the elements from the original list, you create a new list which only contains the elements that are not equal to the "valueToDelete".
This could, for example, look like this:
import java.util.ArrayList;
import java.util.List;
public class QuickListRemove
{
public static void main(String[] args)
{
List<String> size = new ArrayList<String>();
size = deleteAll(size, "value");
}
private static <T> List<T> deleteAll(List<T> list, T valueToDelete)
{
List<T> result = new ArrayList<T>(list.size());
for (T value : list)
{
if (!value.equals(valueToDelete))
{
result.add(value);
}
}
return result;
}
}
If you want to modify the collection while iterating them then you should use Iterators, otherwise you can use the for-each loop.
For -each :
// T is the type f elements stored in myList
for(T val : myList)
{
// do something
}
Try putting a break after you find the element to delete.
2nd question, which is continue of first.
I have got two Lists of strings. There is an List of strings (asu) - M1, M2, M3 ... As well as an List of string (rzs) - M1, M2, M3 and all possible combinations thereof. The need for each element (asu) (for example M1) to find an element in (rzs) (M1, M1M2, ..), which contains (e.g. M1). Example: took M1 from (asu) and will start search for duplicate(contain) in (rzs). We found M1M2 in (rzs), it contains M1. After that we should delete both elements from lists. Great thanks to No Idea For Name helped for modification this code. But the program always fails because AbstractList.remove error. Please help to implementation logic and tuning code!
Imports..........
public class work{
List<string> asu = Arrays.asList("M1","M1","M1","M3","M4","M5","M1","M1","M1","M4","M5","M5");
List<string> rzs = Arrays.asList("M1","M2","M3","M4","M5",
"M1M2","M1M3","M1M4","M1M5","M2M3","M2M4","M2M5","M3M4","M3M5","M4M5"
,"M1M2M3","M1M2M4","M1M2M5","M1M3M4","M1M3M4","M1M4M5","M2M4","M2M5");
public static void main(String[] args) {
work bebebe = new work();
bebebe.mywork();
}
List<string> tmp1 = new ArrayList<string>();
List<string> tmp2 = new ArrayList<string>();
System.out.println(Arrays.deepToString(rzs));
System.out.println(Arrays.deepToString(asu));
for (string curr : asu){
for (string currRzs : rzs){
System.out.println("New iteration ");
if (currRzs.contains(curr)) {
System.out.println("Element ("+curr+") in ASU =
element ("+currRzs+") in RZS");
if(tmp1.contains(curr) == false)
tmp1.add(curr);
if(tmp2.contains(currRzs) == false)
tmp2.add(currRzs);
}
}
}
for (string curr : tmp1){
asu.remove(curr);
}
for (string currRzs : tmp2){
rzs.remove(currRzs);
}
You should try to make use of removeAll() or retainAll() methods of Collection.
For example:
List<String> aList = new ArrayList<String>();
aList.add("a");
aList.add("b");
aList.add("c");
aList.add("d");
aList.add("e");
List<String> bList = new ArrayList<String>();
bList.add("b");
bList.add("e");
bList.add("d");
aList.removeAll(bList);
will give you the "a" and "c" elements left in aList
While if you try to make use of retainAll() method:
aList.retainAll(bList);
will give you "b", "d" and "e" elements left in aList;
retainAll() is used to remove all the elements of the invoking collection which are not part of the given collection.
removeAll() is used to remove all the elements of a collection from another collection.
So, it all depends on your use-case.
EDIT
If in any case you want to remove some elements from these collections while iterating conditionally then you should first obtain the Iterator<Type> then call the remove() method over it.
Like:
while(iterator.hasNext()){
String str = iterator.next();
if(str.equals('test')){
iterator.remove();
}
}
Don't remove items from list using foreach loop. Use classic for and iterate over elements, and when removing item, decrease iterator.
To safely remove elements while iterating use Iterator.remove method:
The behavior of an iterator is unspecified if the underlying
collection is modified while the iteration is in progress in any way
other than by calling this method.
Iterator<String> i = tmp1.iterator();
while (i.hasNext()) {
i.next(); // must be called before remove
i.remove();
}
Also it is easier to remove all collection from another by simply calling:
asu.removeAll(tmp1);
instead of List you can use Set, which will remove automatically the duplicate elements...
You can use removeAll() method to remove collection of elements from the list instead of removing one by one.
use
asu.removeAll(tmp1);
instead of
for (string curr : tmp1)
{
asu.remove(curr);
}
and use
rzs.removeAll(tmp2);
instead of
for (string currRzs : tmp2)
{
rzs.remove(currRzs);
}
update
I trace out your problem.The problem lies in Arrays.asList() method.
According to Arrays#asList
asList() returns "a fixed-size list backed by the specified array". If you want to resize the array, you have to create a new one and copy the old data. Then the list won't be backed by the same array instance.
So create a duplicate ArrayList for the lists.Like this
List<string> asuDuplicat = new ArrayList<string>(asu);
List<string> rzsDuplicat = new ArrayList<string>(rzs);
use asuDuplicat,rzsDuplicat.
asuDuplicat.removeAll(tmp1);
rzsDuplicat.removeAll(tmp2);
I have this code:
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, ", ");
}
I get this:
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)
How would be this the correct way? Java.15
Quite a few problems with your code:
On Arrays.asList returning a fixed-size list
From the API:
Arrays.asList: Returns a fixed-size list backed by the specified array.
You can't add to it; you can't remove from it. You can't structurally modify the List.
Fix
Create a LinkedList, which supports faster remove.
List<String> list = new LinkedList<String>(Arrays.asList(split));
On split taking regex
From the API:
String.split(String regex): Splits this string around matches of the given regular expression.
| is a regex metacharacter; if you want to split on a literal |, you must escape it to \|, which as a Java string literal is "\\|".
Fix:
template.split("\\|")
On better algorithm
Instead of calling remove one at a time with random indices, it's better to generate enough random numbers in the range, and then traversing the List once with a listIterator(), calling remove() at appropriate indices. There are questions on stackoverflow on how to generate random but distinct numbers in a given range.
With this, your algorithm would be O(N).
This one has burned me many times. Arrays.asList creates an unmodifiable list.
From the Javadoc: Returns a fixed-size list backed by the specified array.
Create a new list with the same content:
newList.addAll(Arrays.asList(newArray));
This will create a little extra garbage, but you will be able to mutate it.
Probably because you're working with unmodifiable wrapper.
Change this line:
List<String> list = Arrays.asList(split);
to this line:
List<String> list = new LinkedList<>(Arrays.asList(split));
The list returned by Arrays.asList() might be immutable. Could you try
List<String> list = new ArrayList<>(Arrays.asList(split));
I think that replacing:
List<String> list = Arrays.asList(split);
with
List<String> list = new ArrayList<String>(Arrays.asList(split));
resolves the problem.
Just read the JavaDoc for the asList method:
Returns a {#code List} of the objects
in the specified array. The size of
the {#code List} cannot be modified,
i.e. adding and removing are
unsupported, but the elements can be
set. Setting an element modifies the
underlying array.
This is from Java 6 but it looks like it is the same for the android java.
EDIT
The type of the resulting list is Arrays.ArrayList, which is a private class inside Arrays.class. Practically speaking, it is nothing but a List-view on the array that you've passed with Arrays.asList. With a consequence: if you change the array, the list is changed too. And because an array is not resizeable, remove and add operation must be unsupported.
The issue is you're creating a List using Arrays.asList() method with fixed Length
meaning that
Since the returned List is a fixed-size List, we can’t add/remove elements.
See the below block of code that I am using
This iteration will give an Exception Since it is an iteration list Created by asList() so remove and add are not possible, it is a fixed array
List<String> words = Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog");
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}
This will work fine since we are taking a new ArrayList we can perform modifications while iterating
List<String> words1 = new ArrayList<String>(Arrays.asList("pen", "pencil", "sky", "blue", "sky", "dog"));
for (String word : words) {
if ("sky".equals(word)) {
words.remove(word);
}
}
Arrays.asList() returns a list that doesn't allow operations affecting its size (note that this is not the same as "unmodifiable").
You could do new ArrayList<String>(Arrays.asList(split)); to create a real copy, but seeing what you are trying to do, here is an additional suggestion (you have a O(n^2) algorithm right below that).
You want to remove list.size() - count (lets call this k) random elements from the list. Just pick as many random elements and swap them to the end k positions of the list, then delete that whole range (e.g. using subList() and clear() on that). That would turn it to a lean and mean O(n) algorithm (O(k) is more precise).
Update: As noted below, this algorithm only makes sense if the elements are unordered, e.g. if the List represents a Bag. If, on the other hand, the List has a meaningful order, this algorithm would not preserve it (polygenelubricants' algorithm instead would).
Update 2: So in retrospect, a better (linear, maintaining order, but with O(n) random numbers) algorithm would be something like this:
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--;
}
}
This UnsupportedOperationException comes when you try to perform some operation on collection where its not allowed and in your case, When you call Arrays.asList it does not return a java.util.ArrayList. It returns a java.util.Arrays$ArrayList which is an immutable list. You cannot add to it and you cannot remove from it.
I've got another solution for that problem:
List<String> list = Arrays.asList(split);
List<String> newList = new ArrayList<>(list);
work on newList ;)
Replace
List<String> list=Arrays.asList(split);
to
List<String> list = New ArrayList<>();
list.addAll(Arrays.asList(split));
or
List<String> list = new ArrayList<>(Arrays.asList(split));
or
List<String> list = new ArrayList<String>(Arrays.asList(split));
or (Better for Remove elements)
List<String> list = new LinkedList<>(Arrays.asList(split));
Yes, on Arrays.asList, returning a fixed-size list.
Other than using a linked list, simply use addAll method list.
Example:
String idList = "123,222,333,444";
List<String> parentRecepeIdList = new ArrayList<String>();
parentRecepeIdList.addAll(Arrays.asList(idList.split(",")));
parentRecepeIdList.add("555");
You can't remove, nor can you add to a fixed-size-list of Arrays.
But you can create your sublist from that list.
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, ", ");
}
*Other way is
ArrayList<String> al = new ArrayList<String>(Arrays.asList(template));
this will create ArrayList which is not fixed size like Arrays.asList
Arrays.asList() uses fixed size array internally.
You can't dynamically add or remove from thisArrays.asList()
Use this
Arraylist<String> narraylist=new ArrayList(Arrays.asList());
In narraylist you can easily add or remove items.
Arraylist narraylist=Arrays.asList(); // Returns immutable arraylist
To make it mutable solution would be:
Arraylist narraylist=new ArrayList(Arrays.asList());
Following is snippet of code from Arrays
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;
so what happens is that when asList method is called then it returns list of its own private static class version which does not override add funcion from AbstractList to store element in array. So by default add method in abstract list throws exception.
So it is not regular array list.
Creating a new list and populating valid values in new list worked for me.
Code throwing error -
List<String> list = new ArrayList<>();
for (String s: list) {
if(s is null or blank) {
list.remove(s);
}
}
desiredObject.setValue(list);
After fix -
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);