So I have this array, and I want to delete strings that are 2 or 4 characters in length (strings that contain 2 or 4 characters). I am doing this method, and it doesn't work, even though logically, it SHOULD work.
public static void main(String[] args)
{
ArrayList<String> list = new ArrayList<String>();
list.add("This");
list.add("is");
list.add("a");
list.add("test");
for (int i=0; i<list.size(); i++)
{
if(list.get(i).length()==2 || list.get(i).length()==4)
{
list.remove(i);
}
}
}
I'd like to stick to this method of doing it. Can you please give me some suggestions as to how to correct this code?
The output of this code when I run it is:
[is, a]
Even though I want the output to be
[a]
because "is" is 2 characters long.
The list is changing. Iterate from last element to first or use iterator.
PeterPeiGuo is right - you are removing elements which is shifting your index.
This is a prime candidate for an iterator.
Iterator<String> it = list.iterator();
while(it.hasNext()) {
String val = it.next();
if(val.length() == 4 || val.length() == 2) {
it.remove();
}
}
Another option for it:
When you remove one, decrease your index by 1.
By the way, it works, but is not a good coding style.
for (int i=0; i<list.size(); i++)
{
if(list.get(i).length()==2 || list.get(i).length()==4)
{
list.remove(i);
i--;
}
}
Deleting things from the list changes the indexes of the remaining things in the list.
When your code runs, in the first iteration, i is 0 and it deletes the "this" entry at 0.
On the second iteration i is 1 and thus it doesn't check the value at 0, which is now "is" because the "this" was removed.
As PeterPeiGui says in his answer, you can work around it in this particular case just by going backward, but traversing a collection and mutating it simultaneously always has a risk of introducing plenty of confusion.
Related
I have an ArrayList that contains a bunch of words each in their own cell that come from a file. Some of those words are complete word like "physicist, water, gravity". However, other words are just letters that got split throughout the process of the program. For example, "it's" became "it" and "s". As such, I want to remove all of the single letter words except "I" and "A" because these are actual words.
This is the code I have for now:
for(int i=0;i<dictionnary.size();i++) {
if(dictionnary.get(i).compareToIgnoreCase("I")!=0||dictionnary.get(i).compareToIgnoreCase("A")!=0||dictionnary.get(i).length()==1){
dictionnary.remove(i);
}
}
Where dictionnary is my ArrayList. However, when I print out the content of my arrayList the "s" from it's remains. I also know that there was originally a word "E" that got removed throughout the process above. I'm confused as to why the "S" remains and how to fix it.
From my understanding this code goes through the ArrayList and checks if the length of the case is 1 (which is the case for all single letter words) as well as checking if that case is a case of "I" or "A" regardless of if it is capitalized or not. It then removes the cases that don't correspond to the "I" or "A".
Consider using the Collection Iterator for safe removal of elements during iteration.
for (Iterator<String> iter = dictionary.iterator() ; iter.hasNext() ; ) {
String word = iter.next();
if (word.length() == 1
&& !"I".equals(word)
&& !"A".equalsIgnoreCase(word)) {
iter.remove();
}
}
My suggestion is the following:
You can use removeIf in a next way.
removeIf takes a predicate.
public static void main(String[] args) {
List<String> dictionary = new ArrayList<>();
dictionary.add("I");
dictionary.add("A");
dictionary.add("p");
dictionary.add("its");
dictionary.add("water");
dictionary.add("s");
Integer sizeRemove =1;
dictionary.removeIf(
word ->
!"I".equals(word)
&& !"A".equalsIgnoreCase(word)
&& word.length() == sizeRemove
);
System.out.println(dictionary);
}
The output is the following:
[I, A, its, water]
Reference:
https://www.programiz.com/java-programming/library/arraylist/removeif
Use iterators instead. Let's say you have a list of (1,2,3,4,5) and you want to remove the numbers 2 and 3. You start looping through and get to the second element 2. Here your i is 1. You remove that element and go to i=2. What you have now is (1,3,4,5). Since i=2, you have missed one element.
And that's the reason you should use iterators instead. Refer to #vsfDawg answer.
My answer to this question is as follows, but I want to know if I can use this code and what will be the complexity:
import java.util.LinkedHashMap;
import java.util.Map.Entry;
public class FirstNonRepeatingCharacterinAString {
private char firstNonRepeatingCharacter(String str) {
LinkedHashMap<Character, Integer> hash =
new LinkedHashMap<Character, Integer>();
for(int i = 0 ; i< str.length() ; i++)
{
if(hash.get(str.charAt(i))==null)
hash.put(str.charAt(i), 1);
else
hash.put(str.charAt(i), hash.get(str.charAt(i))+1);
}
System.out.println(hash.toString());
for(Entry<Character, Integer> c : hash.entrySet())
{
if(c.getValue() == 1)
return c.getKey();
}
return 0 ;
}
public static void main(String args[])
{
String str = "geeksforgeeks";
FirstNonRepeatingCharacterinAString obj =
new FirstNonRepeatingCharacterinAString();
char c = obj.firstNonRepeatingCharacter(str);
System.out.println(c);
}
}
Your question about whether you "can use this code" is a little ambiguous - if you wrote it, I'd think you can use it :)
As for the complexity, it is O(n) where n is the number of characters in the String. To count the number of occurrences, you must iterate over the entire String, plus iterate over them again to find the first one with a count of 1. In the worst case, you have no non-repeating characters, or the only non-repeating character is the last one. In either case, you have to iterate over the whole String once more. So it's O(n+n) = O(n).
EDIT
There is a bug in your code, by the way. Because you are using an insertion-order LinkedHashMap, each call to put(Character,Integer) results in a re-ordering of the underlying list. You should probably use a LinkedHashMap<Character,int[]> instead, and check for the presence of keys before putting. If they exist, then merely increment the value stored in the int[] to avoid re-ording the map by making another put call. Even so, the resulting list will be in reverse order from the way you iterate over it, so the first non-repeating character will be the last one you find when iterating over it whose value is 1. Alternatively, you could just iterate in reverse in your first for loop, then you avoid having to always go through the entire Entry set if the first non-repeating character comes sooner than the final character in the original String.
What is the simplest way to add an item between all items in a List?
For example, a List of Strings
{"1", "2", "3"}
becomes
{"1", ",", "2", "," "3"}
Edit 1
My first naive attempt which crashed and burned HARD (don't do this):
for (int i=0; i < list.size(); i++) {
if(i==0) continue;
if(i==list.size()) continue;
list.add(i, new String(","));
}
You have a very functional way to think about your problem. Here is what I would do:
// use ArrayList, it is very easy to handle and comes with all necessary methods as Payam already said
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
// this is the actual solution:
for (int i = 1; i < list.size(); i += 2) {
list.add(i, ",");
}
// and this is just for testing (printing) the list
for (String s : list) {
System.out.print("'"+s + "' ");
}
Expected outcome would be:
'1' ',' '2' ',' '3'
So, you loop through your list.
First: your index i starts at 1 (you don't want to add anything before the first element).
Then instead of incrementing your index by one (i++) you increment it by two (i+=2). That way your index points to every even position in the list.
At last you want to use add(index, value) to add a new value (here: ,) to the list at the specified position. Adding a new value to position any position will shift the following elements of your list "one to the left". They will not be overwritten (only moved to another index) and you can still loop your list from the beginning to the end, since you don't care if it grows in size or not.
Why don't you just use an ArrayList it's way easier to add and remove items.
Adding:
ArrayList<Integer> arrlist = null;
arrlist.add(0, 2);
....
Removing:
arrlist.remove(index);
I have an array of 10,000 elements and i want to loop through and find a particular number say '6573'.
Example
for(int i=0;i<=user.length;i++)
{
if(user[i]=="6573")
System.out.println("Found it!!!");
}
Could you please suggest a way to improve the performance of the code.
Thanks
Use .equals instead of == to compare strings
Break when a match is found
he end condition must be i < user.length to prevent ArrayIndexOutOfBoundsException:
--
for(int i = 0; i < user.length; i++) {
if("6573".equals(user[i])) {
System.out.println("Found it!!!");
break;
}
}
Note that I inverted the .equals() call to prevent NullPointerException if the array contains null values.
If you need to do it once then that's about it. If you try to find several users in that list then you could use a set for O(1) search:
Set<String> set = new HashSet<>(Arrays.asList(user));
if(set.contains("6573"))
System.out.println("Found it!!!");
And it may actually make sense to store your users directly in that set in the first place instead of using an array.
if the array elements is in order(sorted) then u can use the binary search .. it will increase the performance of your program.
Sort the Array using sort() (efficiency O(n Log n) and use binary search (O(log n) ) .. I think this will be more efficient than your current efficency i.e, O(n).. Just giving details of #abhi's answer...
try like this
int index = -1;
boolean found = false;
for(int i = 0; i < array.length; i++)
{
if(array[i].equalsIgnoreCase(userInput))
{
index = i;
found = true;
break;
}
}
you could use multi-threading and make for example 2 pointers, one travel from the start of the array and one form the end till the middle of the array.
It will use more processing but less time.
I'm looping into a number of rows and trying to filter these rows with some if statements. within each if statement I need to have an index for a number of elements. I could have done that using 2d String[][] but the problem is I don't know what is the size of each row at this stage.
I'm looking to store my data like the following :
0 1 3 4 5 6 7 etc..
0 str str str str str str str
1 str str str
2
3 str str str str str str
Any suggestion would be appreciate it
Edit:
Sorry if my question wasn't clear. But I'll explain it more here.
My Loop looks like this:
newArrayList
for (i; i < List ;i++)
{
if(...)
{
newArrayList.add.(0, List.get(i));
} else if(...)
{
newArrayList.add.(2, List.get(i));
} else if(...)
{
newArrayList.add.(6, List.get(i));
}
}
The above code doesn't work but I'm just trying to explain what I need to do actually! My if statements can occur several times and I would like to consider an index for each if statement expectation plus a set of strings. Thanks.
You could try an ArrayList of ArrayList's:
ArrayList<ArrayList<String>> strings = new ArrayList<ArrayList<String>>();
strings.add(new ArrayList<String>()); // Adding a first array to the 'array of arrays'
strings.get(0).add("String1"); // Add a string to the first array,
// Similar to: arr[0][0] = "String1"
//To access them element by element use a double for, note that "s" is each element
for (ArrayList<String> l : strings) {
for (String s : l) {
}
}
PS: An ArrayList<Object> is like an array Object[] but more flexible. It has some useful methods like:
arr_list.get(index); // Getting an object in position 'index'
arr_list.add(object); // Adding an element (Similar to assignment in arrays)
Edit
If you know the number of "rows" then you have to add them to the array of arrays. With this for you are "creating the empty rows of your array":
Rows:
0
1
...
n
for (int i = 0; i < n; i++) { // n is the number of "rows"
strings.add(new ArrayList<String>());
}
Then add an element to a "row":
strings.get(0).add("String1"); // get(0) to obtain the first row, get(1) to obtain the second...
If your index is consecutive form 0 to n and you are inserting them in that order, but n is not known in advance: There are two classical solution:
1) If you do it with a pre-allocated fixed array, you obviously need two passes. The first pass is scanning the row and counting the elements. The second pass is then creating the index.
2) You can do it with a collection allowing dynamic growth via an .add(item) method, like List
If you will convert the collection to an fixed size array later, then it is maybe faster to use method 1) since the add method may be slower due to memory management / allocation / re-allocation.
If your index is consecutive form 0 to n and n is known in advance, but you are inserting the elements not in that order:
You should use solution 1) above.
If your index is not consecutive and n is known known in advance:
3) You create a Map<Integer,String> strings and add the elements via strings.put(index, string) (in any order).
If your index is not unique (as we have finally found out):
4) You crate a Map<Integer,ArrayList<String>> stringMap and add elements via
addStringForIndex(String string, Integer index)
{
listForString = stringMap.get(index);
if(listForString == null) {
listForString = new ArrayList<String>;
map.put(index, listForString);
}
listForString.add(string);
}
If you don't know the size of your array, you could use a List implementation, for example:
ArrayList<ArrayList<String>> 2D = new ArrayList<ArrayList<String>>();
And then use a for-each loop