Remove only one element from duplicated list - java

I have a simple list with same elements:
private List<String> boxes = new ArrayList<>();
boxes.add("100");
boxes.add("20");
boxes.add("20");
boxes.add("5");
boxes.add("5");
boxes.add("5");
boxes.add("5");
boxes.add("5");
boxes.add("Extra life");
boxes.add("Game over");
boxes.add("Game over");
boxes.add("Game over");
I would like to remove a "Game over" value from this list, but only one, not all three. How can I do it? I tried to call remove method on this list but it removes all threee elements.

You can use this overload of the remove method:
boxes.remove("Game over");

public static void remove(List<String> boxes, String str) {
int index = boxes.indexOf(str);
if(index >= 0)
boxes.remove(index);
}
One thing about it. I am worrying about concrete implementation of List<String>. In some cases, boxes.remove(index) could take O(n). So think implementation with Iterator could be better (but not critical). It loop given list only once.
public static void remove(List<String> boxes, String str) {
Iterator<String> it = boxes.iterator();
while (it.hasNext()) {
if (it.next().equals(str)) {
it.remove();
break;
}
}
}
Moreover, as mentioned by #Andreas, List.remove(Object) removes only first found element. Approach that you tried seems to be working correctly:
public static void remove(List<String> boxes, String str) {
boxes.remove(str);
}

Related

Iterating through sets

I am writing a program that will receive a list of words. After that, it will store the repeated words and the non repeated into two different lists. My code is the following:
public class Runner
{
public static void run (Set<String> words)
{
Set<String> uniques= new HashSet<String>();
Set<String> dupes= new HashSet<String>();
Iterator<String> w = words.iterator();
while (w.hasNext())
{
if (!(uniques.add(w.next())))
{
dupes.add(w.next());
}
else
{
uniques.add(w.next());
}
}
System.out.println ("Uniques: "+ uniques);
System.out.println ("Dupes: "+ dupes);
}
}
However, the output for the following:
right, left, up, left, down
is:
Uniques: [left, right, up, down]
Dupes: []
and my desired would be:
Uniques: [right, left, up, down]
Dupes: [ left ]
I want to achieve this using sets. I know it would be way easier to just an ArrayList but I am trying to understand sets.
The reason for your problem is that the argument words is a Set<String>. A set by definition will not contain duplicates. The argument words should be a List<String>. The code also makes the mistake of calling w.next() twice. A call to the next() will cause the iterator to advance.
public static void run(List<String> words) {
Set<String> uniques= new HashSet<String>();
Set<String> dupes= new HashSet<String>();
Iterator<String> w = words.iterator();
while(w.hasNext()) {
String word = w.next();
if(!uniques.add(word)) {
dupes.add(word);
}
}
}
You are doing uniques.add(w.next()) twice. Why?
Also, don't keep calling w.next() - this makes the iteration happen. Call it once and keep a local reference.
Use:
String next = w.next();
if(uniques.contains(next)) {
// it's a dupe
} else {
// it's not a dupe
}

Interation of inner arraylist of arraylist of arraylists

I'm trying to make a arraylist of arraylists. My code is all over the place, I have just been adding stuff and trying trial by error. In the end what I'm trying to do is, say i have a car... it has speed, miles, mpg, and if they want to buy it add it to the arraylist of arraylists, and later be able to get a list of the cars owned, just to give you a idea of what I'm trying to do. idk if it helps, or maybe there's a better way to do it. I just need help with the iteration of the inner array, the rest i can figure out. Right now it just iterates the main arraylist and shows everything in there looking like a array. I rather use for loops then iterate class, but how ever it works is good for me.
public class Thelist {
String a ="aa";
String b ="bb";
String c ="cc";
static ArrayList<ArrayList<String>> collection = new ArrayList<ArrayList<String>>();
static int count=0;
ArrayList<String> listOfSomething1 = new ArrayList<String>();
public void gg(){
ArrayList<String> listOfSomething1 = new ArrayList<String>();
listOfSomething1.add(a);
listOfSomething1.add(b);
listOfSomething1.add(c);
collection.add(listOfSomething1);
count++;
}
public void jk(int u){
//this one feel like i can make new arraylist and use for loop for the collection size and iterate each one
//but seems pretty hacky to me
ArrayList<String> lis = new ArrayList<String>();
lis.addAll(collection.get(u));
for(int i=0;i<lis.size();i++ ){
System.out.println("each "+i+" "+lis.get(i));
}
}
public void ll(){
System.out.println(collection.size());
System.out.println(collection.get(0).size());
}
public void ccc(String x,String y, String z){
this.a= x;
this.b=y;
this.c=z;
}
public void remo(int r){
collection.remove(0);
count--;
}
public void getcount(){
System.out.println("the count "+count);
}
public void showall(){
//this one shows all of the arraylist as arrays it looks like to me, I want each element
// feel like i should be able to add another for loop to iterate over listOfSomething1
//which is be add to the collection arraylist
// but it don't work tryed for each too
for(int i=0;i < collection.size();i++){
System.out.println("uoo "+collection.get(i));
}
}
}
public class MainActivity extends Activity {
static int oo = 1;
Thelist ll = new Thelist();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void woow(View v){
String gg = Integer.toString(oo);
ll.ccc("phi"+gg, "phil"+gg, "phily"+gg);
ll.gg();
oo++;
}
public void shoo(View v){
ll.showall();
}
}
Just use two nested for loops. The first iterates over the collection, yielding one ArrayList<String> per iteration. Take this list and iterate over it in the second iteration. For the sake of simplicity you can use for-each loops here:
for(ArrayList<String> cars : collection) {
for(String car : cars) {
System.out.println(car);
}
}
public void showall(){
for(int i=0;i < collection.size();i++)
for(int j=0; j< collection.get(i).size();j++)
System.out.println(collection.get(i).get(j));
}

How to create a Java Iterator for 2D array/list

I was recently asked about the question that how to create a Java Iterator for 2D Array, specifically how to implement:
public class PersonIterator implements Iterator<Person>{
private List<List<Person>> list;
public PersonIterator(List<List<Person>> list){
this.list = list;
}
#Override
public boolean hasNext() {
}
#Override
public Person next() {
}
}
1D array is pretty straightforward by using a index to track the position, any idea about how to do it for 2D lists.
In the 1D case you need to keep one index to know where you left, right?
Well, in the 2D case you need two indices: one to know in which sub-list you were working, and other one to know at what element inside that sub-list you left.
Something like this? (Note: untested)
public class PersonIterator implements Iterator<Person>{
// This keeps track of the outer set of lists, the lists of lists
private Iterator<List<Person>> iterator;
// This tracks the inner set of lists, the lists of persons we're going through
private Iterator<Person> curIterator;
public PersonIterator(List<List<Person>> list){
// Set the outer one
this.iterator = list.iterator();
// And set the inner one based on whether or not we can
if (this.iterator.hasNext()) {
this.curIterator = iterator.next();
} else {
this.curIterator = null;
}
}
#Override
public boolean hasNext() {
// If the current iterator is valid then we obviously have another one
if (curIterator != null && curIterator.hasNext()) {
return true;
// Otherwise we need to safely get the iterator for the next list to iterate.
} else if (iterator.hasNext()) {
// We load a new iterator here
curIterator = iterator.next();
// and retry peeking to see if the new curIterator has any elements to iterate.
return hasNext();
// Otherwise we're out of lists.
} else {
return false;
}
}
#Override
public Person next() {
// Return the current value off the inner iterator if we can
if (curIterator != null && curIterator.hasNext()) {
return curIterator.next();
// Otherwise try to iterate along the next list and retry getting the next one.
// This won't infinitely loop at the end since next() at the end of the outer
// iterator should result in an NoSuchElementException.
} else {
curIterator = iterator.next();
return next();
}
}
}

Writing a method with ArrayList of strings as parameters

I am trying to write a method that takes an ArrayList of Strings as a parameter and that places a string of four asterisks in front of every string of length 4.
However, in my code, I am getting an error in the way I constructed my method.
Here is my mark length class
import java.util.ArrayList;
public class Marklength {
void marklength4(ArrayList <String> themarklength){
for(String n : themarklength){
if(n.length() ==4){
themarklength.add("****");
}
}
System.out.println(themarklength);
}
}
And the following is my main class:
import java.util.ArrayList;
public class MarklengthTestDrive {
public static void main(String[] args){
ArrayList <String> words = new ArrayList<String>();
words.add("Kane");
words.add("Cane");
words.add("Fame");
words.add("Dame");
words.add("Lame");
words.add("Same");
Marklength ish = new Marklength();
ish.marklength4(words);
}
}
Essentially in this case, it should run so it adds an arraylist with a string of "****" placed before every previous element of the array list because the lengths of the strings are all 4.
BTW
This consists of adding another element
I am not sure where I went wrong. Possibly in my for loop?
I got the following error:
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
at Marklength.marklength4(Marklength.java:7)
at MarklengthTestDrive.main(MarklengthTestDrive.java:18)
Thank you very much. Help is appreciated.
Let's think about this piece of code, and pretend like you don't get that exception:
import java.util.ArrayList;
public class Marklength {
void marklength4(ArrayList <String> themarklength){
for(String n : themarklength){
if(n.length() ==4){
themarklength.add("****");
}
}
System.out.println(themarklength);
}
}
Ok, so what happens if your list just contains item.
You hit the line if(n.length() ==4){, which is true because you are looking at item, so you go execute its block.
Next you hit the line themarklength.add("****");. Your list now has the element **** at the end of it.
The loop continues, and you get the next item in the list, which happens to be the one you just added, ****.
The next line you hit is if(n.length() ==4){. This is true, so you execute its block.
You go to the line themarklength.add("****");, and add **** to the end of the list.
Do we see a bad pattern here? Yes, yes we do.
The Java runtime environment also knows that this is bad, which is why it prevents something called Concurrent Modification. In your case, this means you cannot modify a list while you are iterating over it, which is what that for loop does.
My best guess as to what you are trying to do is something like this:
import java.util.ArrayList;
public class Marklength {
ArrayList<String> marklength4(ArrayList <String> themarklength){
ArrayList<String> markedStrings = new ArrayList<String>(themarklength.size());
for(String n : themarklength){
if(n.length() ==4){
markedStrings.add("****");
}
markedStrings.add(n);
}
System.out.println(themarklength);
return markedStrings;
}
}
And then:
import java.util.ArrayList;
public class MarklengthTestDrive {
public static void main(String[] args){
ArrayList <String> words = new ArrayList<String>();
words.add("Kane");
words.add("Cane");
words.add("Fame");
words.add("Dame");
words.add("Lame");
words.add("Same");
Marklength ish = new Marklength();
words = ish.marklength4(words);
}
}
This...
if(n.length() ==4){
themarklength.add("****");
}
Is simply trying to add "****" to the end of the list. This fails because the Iterator used by the for-each loop won't allow changes to occur to the underlying List while it's been iterated.
You could create a copy of the List first...
List<String> values = new ArrayList<String>(themarklength);
Or convert it to an array of String
String[] values = themarklength.toArray(new String[themarklength.size()]);
And uses these as you iteration points...
for (String value : values) {
Next, you need to be able to insert a new element into the ArrayList at a specific point. To do this, you will need to know the original index of the value you are working with...
if (value.length() == 4) {
int index = themarklength.indexOf(value);
And then add a new value at the required location...
themarklength.add(index, "****");
This will add the "****" at the index point, pushing all the other entries down
Updated
As has, correctly, been pointed out to me, the use of themarklength.indexOf(value) won't take into account the use case where the themarklength list contains two elements of the same value, which would return the wrong index.
I also wasn't focusing on performance as a major requirement for the providing a possible solution.
Updated...
As pointed out by JohnGarnder and AnthonyAccioly, you could use for-loop instead of a for-each which would allow you to dispense with the themarklength.indexOf(value)
This will remove the risk of duplicate values messing up the index location and improve the overall performance, as you don't need to create a second iterator...
// This assumes you're using the ArrayList as the copy...
for (int index = 0; index < themarklength.size(); index++) {
String value = themarklength.get(index);
if (value.length() == 4) {
themarklength.add(index, "****");
index++;
But which you use is up to you...
The problem is that in your method, you didn't modify each string in the arraylist, but only adds 4 stars to the list. So the correct way to do this is, you need to modify each element of the arraylist and replace the old string with the new one:
void marklength4(ArrayList<String> themarklength){
int index = 0;
for(String n : themarklength){
if(n.length() ==4){
n = "****" + n;
}
themarklength.set(index++, n);
}
System.out.println(themarklength);
}
If this is not what you want but you want to add a new string "**" before each element in the arraylist, then you can use listIterator method in the ArrayList to add new additional element before EACH string if the length is 4.
ListIterator<String> it = themarklength.listIterator();
while(it.hasNext()) {
String name = it.next();
if(name.length() == 4) {
it.previous();
it.add("****");
it.next();
}
}
The difference is: ListIterator allows you to modify the list when iterating through it and also allows you to go backward in the list.
I would use a ListIterator instead of a for each, listiterator.add likely do exactly what you want.
public void marklength4(List<String> themarklength){
final ListIterator<String> lit =
themarklength.listIterator(themarklength.size());
boolean shouldInsert = false;
while(lit.hasPrevious()) {
if (shouldInsert) {
lit.add("****");
lit.previous();
shouldInsert = false;
}
final String n = lit.previous();
shouldInsert = (n.length() == 4);
}
if (shouldInsert) {
lit.add("****");
}
}
Working example
Oh I remember this lovely error from the good old days. The problem is that your ArrayList isn't completely populated by the time the array element is to be accessed. Think of it, you create the object and then immediately start looping it. The object hence, has to populate itself with the values as the loop is going to be running.
The simple way to solve this is to pre-populate your ArrayList.
public class MarklengthTestDrive {
public static void main(String[] args){
ArrayList <String> words = new ArrayList<String>() {{
words.add("Kane");
words.add("Cane");
words.add("Fame");
words.add("Dame");
words.add("Lame");
words.add("Same");
}};
}
}
Do tell me if that fixes it. You can also use a static initializer.
make temporary arraylist, modify this list and copy its content at the end to the original list
import java.util.ArrayList;
public class MarkLength {
void marklength4(ArrayList <String> themarklength){
ArrayList<String> temp = new ArrayList<String>();
for(String n : themarklength){
if(n.length() ==4){
temp.add(n);
temp.add("****");
}
}
themarklength.clear();
themarklength.addAll(temp);
System.out.println(themarklength);
}
}

Removing a String from an ArrayList

So I have a problem that takes the names of people from a user and stores them in an ArrayList(personalNames). After that I need to take that list and remove any name that has anything besides letters a-z (anything with numbers or symbols) in it and put them into a separate ArrayList(errorProneNames) that holds the errors. Could someone help me with the removal part?
public class NameList {
public static void main(String[] args) {
ArrayList<String> personalNames = new ArrayList<String>();
Scanner input = new Scanner(System.in);
String answer;
do{
System.out.println("Enter the personal Names: ");
String names = input.next();
personalNames.add(names);
System.out.println("would you like to enter another name (yes/no)?");
answer = input.next();
} while (answer.equalsIgnoreCase("yes"));
ArrayList<String> errorProneNames = new ArrayList<String>();
}
}
If it's the "how do I remove an element from an ArrayList<>" part which is causing problems, and you want to check all the values, you probably want to use an Iterator and call remove on that:
for (Iterator<String> iterator = personalNames.iterator(); iterator.hasNext(); ) {
String name = iterator.next();
if (isErrorProne(name)) {
iterator.remove();
}
}
Note that you mustn't remove an element from a collection while you're iterating over it in an enhanced-for loop except with the iterator. So this would be wrong:
// BAD CODE: DO NOT USE
for (String name : personalNames) {
if (isErrorProne(name)) {
personalNames.remove(name);
}
}
That will throw a ConcurrentModificationException.
Another option would be to create a new list of good names:
List<String> goodNames = new ArrayList<>();
for (String name : personalNames) {
if (!isErrorProne(name)) {
goodNames.add(name);
}
}
Now, if your real problem is that you don't know how to write the isErrorProne method, that's a different matter. I suspect that you want to use a regular expression to check that the name only contains letters, spaces, hyphens, and perhaps apostrophes - but you should think carefully about exactly what you want here. So you might want:
private static boolean isErrorProne(String name) {
return !name.matches("^[a-zA-Z \\-']+$");
}
Note that that won't cope with accented characters, for example. Maybe that's okay for your situation - maybe it's not. You need to consider exactly what you want to allow, and adjust the regular expression accordingly.
You may also want to consider expressing it in terms of whether something is a good name rather than whether it's a bad name - particularly if you use the last approach of building up a new list of good names.
Here is your solution :
String regex = "[a-zA-Z]*";
for (String temp : personalNames ) {
if (!temp.matches(regex)){
errorProneNames.add(temp);
personalNames.remove(temp);
}
}
You can use the remove() method of ArrayList
personalNames.remove("stringToBeRemoved");
Lot of overloaded methods are available. You can delete with index, Object(String itself) etc. You can see Javadocs for more info.
Also to remove all String having anything but a-z letters you can use regex. Logic is as follows
String regex = "[a-zA-Z]*";
String testString = "abc1";
if(!testString.matches(regex)){
System.out.println("Remove this");
}
As Jon pointed out while iterating over the List do not use the Lists's remove() method but the iterators remove() method.
There are two ways you can do this:
The first is to iterate backwards through the list, remove them, then add them into the second list. I say to do it backwards, because it will change the index.
for (int i = personalNames.size()-1; i >=0; i++) {
if (isBadName(personalNames.get(i)]){
errorProneNames.add(personalNames.get(i));
personalNames.remove(i);
}
}
The second way is to use the Iterator provided by ArrayList (personalNames.iterator()). This will allow you to go forward.
I would probably do this
// Check that the string contains only letters.
private static boolean onlyLetters(String in) {
if (in == null) {
return false;
}
for (char c : in.toCharArray()) {
if (!Character.isLetter(c)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
ArrayList<String> personalNames = new ArrayList<String>();
ArrayList<String> errorProneNames = new ArrayList<String>(); // keep this list here.
Scanner input = new Scanner(System.in);
String answer;
do {
System.out.println("Enter the personal Names: ");
String names = input.next();
if (onlyLetters(names)) { // test on input.
personalNames.add(names); // good.
} else {
errorProneNames.add(names); // bad.
}
System.out
.println("would you like to enter another name (yes/no)?");
answer = input.next();
} while (answer.equalsIgnoreCase("yes"));
}
get an iterator from list, while itr has next element give it to a method for example isNotProneName which takes a String and returns true or false, if the given String matches not your needs. if false returned remove string from itr and add it to the other list
Use regex [a-zA-Z ]+ with String.matches to test error-prone name and Iterator to remove.
Iterator<String> it=personalNames.iterator();
while(it.hasNext()){
String name=it.next();
if(name.matches("[a-zA-Z ]+")){
it.remove();
}
}

Categories

Resources