Convert collection of N items into N collections of 1 item each? - java

In Java is there an easy/convenient way to convert a collection of N items into N collections each with one item? I mean other than manually going through each item in the collection and copy it into a new collection.

Here's a way to do it with one statement in Java 8. l1 is some Collection<T>, and the result is a List<ArrayList<T>> where each ArrayList<T> contains one element from the collection.
List<ArrayList<T>> l2 = l1.stream().map(x -> new ArrayList<>(Arrays.asList(x))).collect(Collectors.toList());
Broken down, this:
Creates a Stream of all elements from the collection;
Maps each element to an ArrayList that contains that element;
Collects the resulting ArrayLists into a List<ArrayList>.

If you are willing to use guava, you could have a Function < E, List< E >> that looks like:
public final class ItemToListFunction<E> implements Function<E, List<E>>
{
public List<E> apply(E input)
{
//if it does not need to be mutable
return Collections.singletonList(input);
//if it does need to be mutable
final List<E> list = new ArrayList<E>();
list.add(input);
return list;
}
}
You can then use one of the transform methods in Collections2, Lists, or Iterables.
The advantage of this approach is that the creation of the internal lists is deferred until actual iteration over the elements.

Related

remove item from comparable array

I'm very new to java and my first question is what is this Comparable thing? and in my sample code, why Class Bag<T extends Comparable<T>>?? What's the purpose?
My second question is how to remove an item from this Comparable array. I have wrote the removeMin method, I have found the item, I named the variable "min", how do I go on and remove this min item from the arrayList? Thanks a lot!
Here's some partial code:
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int MAX_ITEMS = 10; // initial array size
private int size;
private Comparable[] data;
public Bag( ) {
//data = (Comparable []) new Object[MAX_ITEMS];
data = (T []) new Comparable[MAX_ITEMS];
size = 0;
}
public Comparable removeMin(){
Iterator<T> iterator=iterator();
T min = iterator.next();
while (iterator.hasNext())
{
T next = iterator.next();
if (min.compareTo(next) > 0)
min = next;
****************************************************
How to remove this min item?
****************************************************
}
return min;
}
What is this Comparable thing?
It is a generic interface that can be implemented by classes whose instances you need to be able to compare with each other. Comparable<T> has a single method int compareTo<other T>. The implementation of the method is supposed to compare this with the other instance
In my sample code, why class Bag<T extends Comparable<T>>? What's the purpose?
This is saying that your Bag class is a generic class with a type parameter T. The T extends Comparable<T> bits is saying that T must be some class that implements Comparable<T>.
My second question is how to remove an item from this Comparable array.
That is for you to figure out, based on your knowledge of how arrays work. The big constraint you have to deal with is that an array's size cannot be changed, so there is no magical operation that will simply remove something from the middle of the array.
There are two approaches:
Create a new array containing just the elements that you don't want to be removed. (Hint: copy them)
Move the elements around in the existing array to "fill the hole" left when you conceptually remove an element. (Hint: notice the size field. What is it there for?)
Assuming that you wrote the removeMin method from scratch, I think you have gone down a blind alley with trying to use an iterator there1. Try coding it to operate directly on the data array.
The removeMin problem has two parts:
Find the index in data for the smallest element
Remove the element at that index
Hint: the first part requires that you look at every element ... and this has to be done before you do the removal. This should be reflected in your code.
1 - If you were using an ArrayList<T> or similar, then using data.iterator() would be a reasonable choice. The problem is that arrays don't directly support the Iterable API.
Now if you are required to make your Bag class implement Iterable<T>, then you could use the iteration mechanism you implemented for that purpose in your removeMin method. But even there, the API is not ideal for the purpose. You would still need to iterate the collection twice. Once to find the smallest element, and a second time to remove it. And removal via an iterator means that the iterator would need to implement the optional Iterator.remove() method .... which brings you back full circle.
It is the java.lang.Comparable interface. <T extends Comparable<T>> is a generic type, at compile time Java will require that an instance provide an implementation of int compareTo(T o) which (from the Javadoc) returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object. Also, you might back your Bag with a Collection (instead of an array), like
class Bag<T extends Comparable<T>> implements Iterable<T> {
private List<T> al = new ArrayList<>();
public Bag() {
super();
}
public T removeMin() {
Iterator<T> iterator = iterator();
T min = iterator.hasNext() ? iterator.next() : null;
while (iterator.hasNext()) {
T next = iterator.next();
if (min.compareTo(next) > 0) {
min = next;
}
}
if (min != null) {
iterator = iterator();
while (iterator.hasNext()) {
T next = iterator.next();
if (min.compareTo(next) == 0) {
iterator.remove();
break;
}
}
}
return min;
}
#Override
public Iterator<T> iterator() {
return al.iterator();
}
}
Note that Iterator.remove() says (in part) 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.
The comparable interface is implemented in order to define a comparison mechanism to your custom types.
array are usually size fixed so you cannot just remove an item without copying the remaining ones to a new array. I suggest to change your array to dynamic list:
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int size;
private LinkedList<T> data;
public Bag() {
data = new LinkedList<T>();
size = 0;
}
public Comparable removeMin() {
Iterator<T> iterator = iterator();
T min = iterator.next();
while (iterator.hasNext()) {
T next = iterator.next();
if (min.compareTo(next) > 0)
min = next;
data.remove(min);
}
return min;
}
}
what is this Comparable thing
In simplest term it specifies how the items can be compared to each other . For example in your case your class Bag may contain any item so you used generic type T but you want your items to be comparable to each other too, so you used T extends Comparable<T>
The Comparable interface has a method compareTo which is used to compare the items. You can read more about it in JLS.
Now you may be wondering why do I need to compare items?
Imagine if you have no way to compare then how can you say 5 is a bigger number than 1 or why A comes before B in alphabets. They do so because we have some order for them and based on them we can compare then. Similarly you may like a items in your bag to be comparable.
how to remove an item from this Comparable array
To iterate over the items you already seem to use an iterator
Iterator<T> iterator=iterator();
T min = iterator.next();
You can use same iterator to remove the item if it matches your condition. So your code should be iterator.remove(). But you should also ensure for null check and existence check at all relevant places

Remove and collect elements with Java streams

Suppose I have a Collection, and a Predicate that matches elements I'd like to remove from the Collection. But I don't just want to discard them, I want to move the matched elements into a new collection. I'd do something like this in Java 7:
List<E> removed = new LinkedList<>();
for (Iterator<E> i = data.iterator(); i.hasNext();) {
E e = i.next();
if (predicate.test(e)) {
removed.add(e);
i.remove();
}
}
I'm curious if there's a streams / Java 8 way to do it. Collections.removeIf() unfortunately simply returns a boolean (not even a count of the number of removed elements? Too bad.) I envision something like this (though of course .removeAndYield(Predicate) doesn't exist):
List<E> removed = data.removeAndYield(predicate).collect(Collectors.toList());
Note: this question was inspired by a similar question; this question is about the more general case of getting a stream over the items removed from a collection. As pointed out in the linked question, the imperative solution may be more readable, but I'm curious if this is even possible with streams.
Edit: Clearly we can split the task into two separate steps, and assuming the appropriate data structures it will be efficient. The question is can this be done on arbitrary collections (which may not have efficient .contains() etc.).
If you don't mind, let me bend your requirements a little bit. :-)
One characteristic of the desired result is that the matching elements should end up in one collection, and the non-matching elements should end up in a different collection. In the pre-Java-8 mutative world, the easiest way to think about getting a collection of non-matching elements is to remove the matching elements from the original collection.
But is removal -- modification of the original list -- an intrinsic part of the requirement?
If it isn't, then the result can be achieved via a simple partitioning operation:
Map<Boolean, List<E>> map = data.stream().collect(partitioningBy(predicate));
The result map is essentially two lists, which contain the matching (key = true) and non-matching (key = false) elements.
The advantage is that this technique can be done in one pass and in parallel if necessary. Of course, this creates a duplicate list of non-matching elements compared to removing the matches from the original, but this is the price to pay for immutability. The tradeoffs might be worth it.
I'd keep it simple:
Set<E> removed = set.stream()
.filter(predicate)
.collect(Collectors.toSet());
set.removeAll(removed);
If you want a functional way to do this, you could write your own method.
static <E> Set<E> removeIf(Collection<? extends E> collection, Predicate<? super E> predicate) {
Set<E> removed = new HashSet<>();
for (Iterator<? extends E> i = collection.iterator(); i.hasNext();) {
E e = i.next();
if (predicate.test(e)) {
removed.add(e);
i.remove();
}
}
return removed;
}
This could be used to remove all odd numbers from a List.
Set<Integer> set = new HashSet<>(Arrays.asList(1, 2, 3, 4, 5, 6));
Set<Integer> removed = removeIf(set, i -> i % 2 != 0);
System.out.println(set);
System.out.println(removed);
Just write yourself a reusable function like this:
/**
* Removes all matching element from iterator
*
* #param it
* #param predicate
*/
public static <E> void removeMatching(final Iterator<E> it, final Predicate<E> predicate) {
while (it.hasNext()) {
final E e = it.next();
if (predicate.test(e)) {
it.remove();
}
}
}
I have also not found a pre-existing solution for Streams. Using iterator.remove() requires less memory than a temporary set.

How to sort a HashSet?

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.

Scan 2D ArrayList for unique elements in the first list

i've been stuck for hours now and can't find a solution.
I want to compare two ArrayLists where i want to put each unique element from one of the list into another arrayList.
For example, if my one arrayList contain {0,1,2,3} and i want to compare it to {{1},{2},{3}} i want to recieve {2} in my 'unqiue' arraylist
please help me
AFTER EDIT
I will be more specific. ArrayList1={0,1,2,3,4} and ArrayList2={{0, 1} {0,1,2}} So what i want is to have the only unique from ArrayList1 in a single ArrayList. in this example i want ArrayList3= {3,4}
You can use method boolean removeAll(Collection c) of List.
It will removes all the elements that are contained in the specified collection from this list. So after invoking this your list will contain unique elements.
Suppose you have arrayList1 and arrayList2 the you can compare them like this:
arrayList1.removeAll(arrayList2);
Now arrayList1 contains only unique elements.
If I am interpreting your question correctly, you want to form a new list of common elements in 2 lists? If so, iterate through one of the list and check to see if the second list contains(Object) that element, if so add it to the third list. I cannot provide a code sample at this very moment but when I get to a computer I will be glad to edit this (if necessary).
Edit:
The code would probably look something like this:
private static <T> List<T> getUniqueList(final List<T> first, final List<T> second){
final List<T> unique = new ArrayList<T>();
for(final T element : first)
if(second.contains(element))
unique.add(element);
return unique;
}
Or if you are using Java 8:
private static <T> List<T> getUniqueList(final List<T> first, final List<T> second){
final List<T> unique = new ArrayList<>();
first.stream().filter(second::contains).forEach(unique::add);
return unique;
}

Why do I get an UnsupportedOperationException when trying to remove an element from a List?

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);

Categories

Resources