Removing Strings of given length from an ArrayList? - java

We are given a list of words in the form of an ArrayList as follows:
public ArrayList<String> getListOfStrings(){
ArrayList<String> list = new ArrayList<String>();
list.add("This");
list.add("is");
list.add("an");
list.add("exercise");
list.add("to");
list.add("illustrate");
list.add("the");
list.add("use");
list.add("of");
list.add("ArrayLists");
list.add(".");
return list;
}
How do I write a method that removes all words in that list (i.e. all the objects in the ArrayList) that have the length "len" entered by the user?
I already wrote a method that lists all the words of length "len" entered by the user, and it works, it's as follows:
public ArrayList<String>getWordsWithLength(int len, ArrayList<String> lijst){
ArrayList<String> list = new ArrayList<String>();
for(String woord: lijst){
if(woord.length()==len){
list.add(woord);
}
}
return(list);
}
But as a beginner in java, I'm stuck on how to remove the words of length "len". Please help!
(I am under the impression that you start by removing them from the end of the list, back-to-front as it were)

The way your currently iterating through the list wont allow you to remove it with an exception but an iterator would.
Iterator<String> it = list.iterator();
while(it.hasNext()) {
if([Condition]) {
it.remove();
}
}

Your method can already serve as a removal, just change the == to a !=
public ArrayList<String> getStringsWithoutEqualLength(int len, ArrayList<String> lijst){
ArrayList<String> list = new ArrayList<String>();
for(String woord: lijst){
if(woord.length() != len){
list.add(woord);
}
}
return(list);
}
If what you are attempting to do is remove the elements from lijst, then just reassign the returned list to it.
ArrayList<String> yourList = ...;
yourList = instance.getStringsWithoutEqualLength(someLength, yourList);
You have effectively removed the longer elements and done it faster than if you had used an Iterator. Every time you remove with an Iterator, you have to resize your backing array.

You have to remove values from a List by using an Iterator to prevent a ConcurrentModificationException.
List<String> myList = getListOfStrings();
Iterator<String> it = myList.iterator();
while (it.hasNext()) {
if(it.next().length() == 3){
it.remove();
}
}

You can even use the same method by adding a boolean parameter.
public ArrayList<String>getWordsWithLength(int len, ArrayList<String> lijst, boolean complement){
ArrayList<String> list = new ArrayList<String>();
for(String woord: lijst){
if((woord.length()==len) != complement){
list.add(woord);
}
}
return(list);
}
If you pass in complement as true, if will give you everything with that doesn't have length == len. complement as false will behave as usual.

While I think that #SotiriosDelimanolis's answer is probably what you should use, I also wanted to point out that with Java 8 you can easily do this using a Stream and a Predicate to filter on:
List<String> list2 = list.stream()
.filter(s -> s.length() != 3)
.collect(Collectors.toList());
Here's a full test class:
import java.util.*;
import java.util.stream.*;
class Test {
public static void main(String args[]) {
ArrayList<String> list = new ArrayList<String>();
list.add("This");
list.add("is");
list.add("an");
list.add("exercise");
list.add("to");
list.add("illustrate");
list.add("the");
list.add("use");
list.add("of");
list.add("ArrayLists");
list.add(".");
System.out.println(list);
List<String> list2 = list.stream()
.filter(s -> s.length() != 3)
.collect(Collectors.toList());
System.out.println(list2);
}
}
and my test output:
$ java Test
[This, is, an, exercise, to, illustrate, the, use, of, ArrayLists, .]
[This, is, an, exercise, to, illustrate, of, ArrayLists, .]

in Scala you'd just do
list.filter(_.length != len)

Related

Check if specific element in array contains a certain String. Then delete the element

I have an ArrayList containing: [2x, 5, 6x]. I want to get rid of the elements containing the "x", but the contains() method applies to all of the elements in the ArrayList.
My attempt:
boolean ready = false;
while(!ready){
if(first element in the array contains "x"){
remove that element
Check next element in line
}
When checked all the elements, and removed those which contains "x", set ready to true, and stop the loop.
I want the output to just be: [6]. And then convert it to int, instead of String.
EDIT:
I couldn't get it to work with ArrayList, because I couldn't alter the contents of an ArrayList. Therefore I changed it to a simple array.
The array is now:
String[]tokens = ligning2.split("-|\+|\*|\/");
So the tokens array will keep [2x, 5, 6x]. So how do I delete the elements containing an x, with this kind of Array, instead of Arraylist?
Use an iterator to iterate the List
for each iteration, if the current String contains the "x" String, remove it from the List with Iterator.remove();
For example :
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
String value = list.next();
if(value.contains("x"){
iterator.remove();
}
}
You can use an Iterator for example :
List<String> list = Arrays.asList("Hello", "xyz", "tkx");
Iterator<String> iter = list.iterator();
while (iter.hasNext()) {
if(iter.next().contains("x")){//check if your element contain x
iter.remove();//if yes remove it
}
}
This would be a great opportunity to utilize a lambda when calling List#removeIf.
For example:
List<String> list = Arrays.asList("2x", "5", "6x");
System.out.println(list); // [2x, 5, 6x]
list.removeIf(element -> element.contains("x"));
System.out.println(list); // [5]
Assuming that there can be multiple values that remain in the List which did not contain an "x", you can use a Stream to map each element to its integer value:
List<Integer> newList = list.stream()
.map(Integer::valueOf)
.collect(Collectors.toList());
The entire algorithm can be condensed into the following:
List<Integer> newList = list.stream()
.filter(element -> !element.contains("x"))
.map(Integer::valueOf)
.collect(Collectors.toList());
You can use this program
package com.anand;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.ListIterator;
public class ArrayListRemove {
static ArrayList<String> al=new ArrayList<>(Arrays.asList("6x","8","5x"));
public static void main(String[] args) {
Iterator<String> i=al.iterator();
while(i.hasNext())
{
if(i.next().toString().contains("x"))
{
i.remove();
}
}
ListIterator<String> li= al.listIterator();
while(li.hasNext())
{
System.out.println(li.next());
}
}
}
Please let me know of you want to create a new Arraylist of integers or just the output to be integers. I will make changes accordingly
Easiest thing to do is using Streams. These were added in Java 8 and you can use them in your case to filter certain items from the list and convert them to integers in one run:
List<String> elements = Arrays.asList("2x", "5", "6x");
List<Double> result = elements.stream()
.filter(entry -> !entry.contains("x"))
.map(Double::valueOf) //this assumes that all other entries are valid doubles
.collect(Collectors.toList());

Why is this particular code for comparing arraylists not working?

I have two different arraylists that I want to compare - specifically to check if a certain element of list1 exists in list2.
This is my code:
for (int i = 0; i < list1.size(); i++){
if (list2.contains(list1.get(i))) {
System.out.println ("match");
}
}
Basically I am looping through list1 - and checking if list2 contains element from list1. This if statement is however not being executed - and no values are null.
The logic and code seems OK to me. What is wrong?
If you're trying to find the intersection between two lists, the better approach would be to use retainAll method. Suppose you have two lists such that:
List<String> list1 = asList("Martin", "Eric", "Kent");
List<String> list2 = asList("Kent", "Josh", "Eric");
The following list will hold the intersection between the two:
List<String> intersection = new ArrayList<>(list1);
intersection.retainAll(list2);
After calling retainsAll, intersection will only contains Kent and Eric.
(This is really a comment. Unfortunately, SE has a coincidental coupling between comment vs. answer and formatting options.)
Here is an example of a complete program that tests your code, but works. For clarity, I printed a non-empty string on match. I suggest modifying it by replacing the lists with the failing case. If it fails, post the complete program.
import java.util.Arrays;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<String> listA = Arrays.asList(new String[] { "job" });
List<String> listB = Arrays.asList(new String[] { "bbb", "job" });
System.out.println("One match");
matcher(listA, listB);
}
public static void matcher(List<String> list1, List<String> list2) {
for (int i = 0; i < list1.size(); i++) {
if (list2.contains(list1.get(i))) {
System.out.println("Found one.");
}
}
}
}

Concurrent ModificationException

I have a piece of code and i am not sure why i am getting the concurrentModificationException
import java.util.*;
import java.util.LinkedList;
import java.util.Scanner;
public class CreateList{
List<Integer> nestedList;
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
System.out.println("Enter the Nested List");
CreateList obj = new CreateList();
System.out.println(obj.createNestedList(sc.next()));
}
public List<Integer> createNestedList(String str){
List<Object> aux = new LinkedList<Object>();
nestedList = new LinkedList<Integer>();
for(int itr=0; itr<str.length();itr++){
char c = str.charAt(itr);
if(c != ']' && c != ',')
aux.add(c);
else if(c == ']'){
Object o = aux.subList(aux.lastIndexOf('[')+1,aux.size());
aux = aux.subList(0,aux.lastIndexOf('['));
aux.add(o);// THIS LINE IS THROWING THE EXCEPTION
System.out.println(o);
System.out.println(aux);
}
}
System.out.println(aux);
return nestedList;
}
}
There is no thread using this code other then the main thread. Any idea what am i missing
I think the problem is the use of subLists. Specifically
aux = aux.subList(0,aux.lastIndexOf('['));
And then later
aux.add(o);// THIS LINE IS THROWING THE EXCEPTION
This changes the size of the sublist vs the size of the original list.
The javadoc of sublist says:
The semantics of the list returned by this method become undefined if the backing list (i.e., this list) is structurally modified in any way other than via the returned list. (Structural modifications are those that change the size of this list, or otherwise perturb it in such a fashion that iterations in progress may yield incorrect results.)
The sublist instance returned by .subList() throws an exception if the modcounts of the sublist vs the original list differ.
The solution is to make a new list using the elements from the sublist
aux = new LinkedList<>(aux.subList(0,aux.lastIndexOf('[')));
You need to create another list instead of getting a sublist and adding a sublist to it.
try something like this instead:
List<T> list = new LinkedList<T>(someList.subList(0,n));
You must use a list iterator if you intend to modify the list while iterating.
List<Object> aux = new LinkedList<Object>();
...
ListIterator<Object> listIterator = aux.listIterator();
// replace the for loop with while. just to make it easier, but can be done with for loop
while(listIterator.hasNext()) {
...
listIterator.add(o);
...
}
If you replace your code with this, it should work.

Remove duplicates from ArrayLists

I have an ArrayList of custom objects. I want to remove duplicate entries.
The objects have three fields: title, subtitle, and id. If a subtitle occurs multiple times, I only need the first item with thats subtitle (ignore the remaining object with that subtitle).
You can put the content of the ArrayList in a TreeSet using a custom Comparator which should return 0 if the two subtitles are the same.
After that you can convert the Set in a List and have the List without "duplicates".
Here is an example for Object, of course you should use the correct class and logic.
public void removeDuplicates(List<Object> l) {
// ... the list is already populated
Set<Object> s = new TreeSet<Object>(new Comparator<Object>() {
#Override
public int compare(Object o1, Object o2) {
// ... compare the two object according to your requirements
return 0;
}
});
s.addAll(l);
List<Object> res = Arrays.asList(s.toArray());
}
List list = (...);
//list may contain duplicates.
//remove duplicates if any
Set setItems = new LinkedHashSet(list);
list.clear();
list.addAll(setItems);
You may need to override "equals()" so that 2 elements are considered equals if they have the same subtitle (or tite and subtitle maybe ?)
List<Item> result = new ArrayList<Item>();
Set<String> titles = new HashSet<String>();
for(Item item : originalList) {
if(titles.add(item.getTitle()) {
result.add(item);
}
}
add() of the Set returns false if the element already exists.
I would suggest using a Set
http://download.oracle.com/javase/6/docs/api/java/util/Set.html
Which by its nature cannot contain duplicate items. You can create a new set from your original ArrayList using
Set myset = new HashSet(myArrayList);
Alternatively, just use a Set from the start, and don't use an ArrayList as it is not performing the function that you require.
If I understand correctly you have an ArrayList<Custom>, let's call it list. Your Custom class has a subtitle field, let's say with a getSubtitle() method that returns String. You want to keep only the first unique subtitle and remove any remaining duplicates. Here's how you can do that:
Set<String> subtitles = new HashSet<String>();
for (Iterator<Custom> it = list.iterator(); it.hasNext(); ) {
if (!subtitles.add(it.next().getSubtitle())) {
it.remove();
}
}
You can use an O(n^2) solution: Use list.iterator() to iterate the list once, and on each iteration, iterate it again to check if there are duplicates. If there are - call iterator.remove(). A variation of this is to use guava's Iterables.filter(list, predicate) where your filtering logic is in the predicate.
Another way (perhaps better) would be to define the equals(..) and hashCode(..) methods to handle your custom equality logic, and then simply construct a new HashSet(list). This will clear duplicates.
Removes any duplicates in a collection, while preserving the order if it is an ordered collection. Efficient enough for most cases.
public static <I, T extends Collection<I>> T removeDuplicates(T collection)
{
Set<I> setItems = new LinkedHashSet<I>(collection);
collection.clear();
collection.addAll(setItems);
return collection;
}
Update for Java8:
Using Java8 streams you can also do pretty trivally.
ArrayList<String> deduped;
deduped = yourArrayList.stream()
.distinct()
.collect(Collectors.toCollection(ArrayList::new));
This also has the advantage over going ArrayList → Set → ArrayList of maintaining ordering.
Use Collections.sort() to sort and use a simple for cycle to catch doubles, e.g.:
Collections.sort(myList);
A previous = null;
for (A elem: myList) {
if (elem.compareTo(previous) == 0) continue;
previous = elem;
[... process unique element ...]
}
This presumes that you'll implement Comparable in your type A.
private static List<Integer> removeDuplicates(List<Integer> list) {
ArrayList<Integer> uniqueList = new ArrayList<Integer>();
for (Integer i : list) {
if (!inArray(i, uniqueList)) {
uniqueList.add(i);
}
}
return uniqueList;
}
private static boolean inArray(Integer i, List<Integer> list) {
for (Integer integer : list) {
if (integer == i) {
return true;
}
}
return false;
}
The solution depends on circumstances.
If you don't have much data then go with a Set Set<T> unique = new HashSet<>(yourList); (use LinkedHashSet if you care about the order. It creates a new collection, but usually it's not a problem.
When you want to modify existing list and don't want to/can't create a new collection, you can remove duplicates like here:
List<Integer> numbers =
new ArrayList<>(asList(1, 1, 2, 1, 2, 3, 5));
System.out.println("Numbers: " + numbers);
ListIterator<Integer> it = numbers.listIterator();
while (it.hasNext()) {
int i = it.nextIndex();
Integer current = it.next();
for (int j = 0; j < i; ++j) {
if (current.equals(numbers.get(j))) {
it.remove();
break;
}
}
}
System.out.println("Unique: " + numbers);
It works in O(n^2), but it works. Similar implementation, but simpler, is when the list is sorted - works in O(n) time. Both implementations are explained at Farenda: remove duplicates from list - various implementations.
In Java 8, you can also do something like this:
yourList.stream().collect(
Collectors.toMap(
obj -> obj.getSubtitle(),
Function.identity(),
(o1,o2) -> o1))
.values();
The trick is to collect stream to map and provide key collision resolver lambda ((o1,o2) -> o1) which always returns its first parameter.
The result is a Collection, not a List but you can easily convert it to a List:
new ArrayList(resultCollection);
List<YourObject> all = ******** // this is the object that you have already and filled it.
List<YourObject> noRepeat= new ArrayList<YourObject>();
for (YourObject al: all) {
boolean isPresent = false;
// check if the current objects subtitle already exists in noRepeat
for (YourObject nr : noRepeat) {
if (nr.getName().equals(al.getName()) {
isFound = true;//yes we have already
break;
}
}
if (!isPresent)
noRepeat.add(al); // we are adding if we don't have already
}
take one new ArrayList Object of same type
one by one add all the old arraylists elements into this new arraylist object
but before adding every object check in the new arraylist that if there is any object with the same subtitle.if new arraylist contains such subtitle don't add it. otherwise add it
Another method using Java 8 streams you can also do pretty cool:
List<Customer> CustomerLists;
List<Customer> unique = CustomerLists.stream().collect(collectingAndThen(
toCollection(() -> new TreeSet<>(comparingLong(Customer::getId))),
ArrayList::new));

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