Finding the powerset of a String - java

I'm trying to write a java method for finding the subset of a string but I keep getting a runtime error I have been unable to debug. Here is the code:
public static List<String> subset(String m, List<String> list){
if (m.length() <= 1){
list.add(m);
return list;
}
else{
String letter = m.substring(0,1);
String rest = m.substring(1,m.length());
for (String x : subset(rest,list)){
list.add(letter + x);
}
list.add(letter);
return list;
}
}

Your problem is that in your for loop, you're iterating through a list that's constantly changing. This gives you a ConcurrentModificationException.
It's better if you make a copy of your list first, before you try to iterate through it. You want something like this in place of your for loop.
List<String> copy = new ArrayList<String>(subset(rest,list));
for (String x : copy){
list.add(letter + x);
}
This works, of course (yes, I've tested it), but it's a bit confusing in the way that you've added SOME elements by recursion and OTHERS by iteration. I think a re-design would be a good idea.

Related

Can you skip parts of an array when using a for-each loop?

I was told to only return strings with a given length from an array. I can do this easy with a regular for loop. but I recently discovered for-each loops and I am trying to learn how to use them. this problem seems doable but I may be wrong.
There is the code I am working on:
public List wordsWithoutList(String[] words, int len) {
String[] temp = new String[0];
for (String i : words) {
if (i.length() != len) {
temp = new String[temp.length + 1];
temp[i] = words[i];
}
}
return temp;
}
That's not the point of a for each loop. You can skip elements (continue) or break out of the loop (break), but you have to call the body for each element.
When you want to just handle a specified range of indexes use the "normal" for-loop.
A couple things.
The big difference between a for loop and a foreach loop is to obfuscate the iterator from the loop, so you don't have to worry about requirements. Otherwise, they work very similarly.
To answer your question - if you add a conditional statement to check for what you don't want, you can "skip" using the continue keyword. continue works like break, but instead of breaking the loop, it simply skips the processing for the current iteration.
You can read more here at Geeks for Geeks.
To return strings with a given length from an array you could use simple if statement:
public List<String> givenLength(String[] words, int len) {
List<String> strings = new ArrayList<>();
for (String word : words) {
if (word.length() == len) {
strings.add(word);
}
}
return strings;
}

How can I test if an array contains each value from map?

I have a map:
Map<String, String> abc = new HashMap<>();
"key1" : "value1",
"key2" : "value2"
And an array:
String[] options= {"value1", "value2", "value3"}
I am creating this array as following (I am using following method to do something else which is not relevant to the question that I am asking here):
public String[] getOptions() {
List<String> optionsList = getOptionsFromAMethod(WebElementA);
String[] options = new String[optionsList.size()];
options = optionsList.toArray(options);
return options;
}
What is the best way to verify if String[] contains each value from Map?
I am thinking about doing this:
for (Object value : abc.values()) {
Arrays.asList(options).contains(value);
}
Explanation
Your current approach creates an ArrayList (from java.util.Arrays, not to confuse with the regular ArrayList from java.util) wrapping the given array.
You then call, for each value of the map, the ArrayList#contains method. However this method is very slow. It walks through the whole list in order to search for something.
Your current approach thus yields O(n^2) which doesn't scale very well.
Solution
We can do better by using a data-structure which is designed for a fast contains query, namely a HashSet.
So instead of putting all your values into an ArrayList we will put them into a HashSet whose contains method is fast:
boolean doesContainAll = true;
HashSet<String> valuesFromArray = new HashSet<>(Arrays.asList(options));
for (String value : abc.values()) {
if (!valuesFromArray.contains(value)) {
doesContainAll = false;
break;
}
}
// doesContainAll now is correctly set to 'true' or 'false'
The code now works in O(n) which is far better and also optimal in terms of complexity.
Of course you can optimize further to speedup by constant factors. For example you can first check the size, if options.length is greater than abc.values().size() then you can directly return with false.
JStream solution
You can also use Java 8 and Streams to simplify the above code, the result and also the procedure behind the scenes is the same:
HashSet<String> valuesFromArray = new HashSet<>(Arrays.asList(options));
boolean doesContainAll = abc.values().stream()
.allMatch(valuesFromArray::contains);
Insights of ArrayList#contains
Let's take a closer look into java.util.Arrays.ArrayList. You can find its code here.
Here is its code for the contains method:
public boolean contains(Object o) {
return indexOf(o) != -1;
}
Lets see how indexOf is implemented:
public int indexOf(Object o) {
E[] a = this.a;
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
So indeed, in all cases the method will traverse from left to right through the source array in order to find the object. There is no fancy method that is able to directly access the information whether the object is contained or not, it runs in O(n) and not in O(1).
Note on duplicates
If either of your data may contain duplicates and you plan to count them individually, then you will need a slightly different approach since contains will not bother for the amount of duplicates.
For this you may collect your abc.values() first into a List for example. Then, every time you checked an element, you will remove the matched element from the List.
Alternatively you can setup a HashMap<String, Integer> which counts for every element its occurrences. Then, every time you checked an element, decrease the counter by one.
You can use https://docs.oracle.com/javase/7/docs/api/java/util/List.html#containsAll(java.util.Collection)
Arrays.asList("value1", "value2", "value3").containsAll(abc.values())
I would recommend using a stream:
final List<String> optionsList = Arrays.asList(options);
abc.values().stream().allMatch(optionsList::contains);

Elements are not being removed from ArrayList

I am trying to remove elements that do not contain a specific string from an arrayList but with no luck. I am using the following code:
ArrayList<String> classes = ClassesRetrieval.getYagoClasses();
Iterator<String> it = classes.iterator();
while(it.hasNext()){
if(it.next().contains("yago")){
it.remove();
}
}
for(String i : classes){
System.out.println(i);
}
I also tried
for(int i=0;i<classes.size();i++){
if(!classes.get(i).contains("yago")){
classes.remove(i);
}
}
for(String i : classes){
System.out.println(i);
}
but with no luck..
I tested you first code on a list I created myself. It worked, but if you want to remove Strings that don't contain "yago", you are missing a !.
ArrayList<String> classes = ClassesRetrieval.getYagoClasses();
Iterator<String> it = classes.iterator();
while(it.hasNext()){
if(!it.next().contains("yago")){
it.remove();
}
}
for(String i : classes){
System.out.println(i);
}
First of all, remove '!' in your second code if(!classes.get(i).contains("yago")), and i think it should work.
If it won't, give some base code of ClassesRetrieval.getYagoClasses();, please.
Using for loops to remove elements is really not recommended. Consider having two consecutive strings, both of which contain "yago". It will remove the first one, increment i and skip the second string (since it now has the index of the first string).
Try a while loop where you increment only if you don't remove the element (or, if you hate branching, reverse the for loop from greater to smaller).
As for your first example, right now it removes all those that do contain "yago". If you put a ! before the condition it should work properly.
I don't see anything wrong with your syntax/logic. However, it is possible that the condition
!classes.get(i).contains("yago")
Is not being met. To test whether this is true, I would print something if the condition yields true. For example:
for(int i=0;i<classes.size();i++){
if(!classes.get(i).contains("yago")){
classes.remove(i);
System.out.println("Condition Met");
}
}
You can even print the deleted element like this:
for(int i=0;i<classes.size();i++){
if(!classes.get(i).contains("yago")){
System.out.println(classes.remove(i));
}
}
I hope you find this helpful.
The second piece of code you showed should work. Why are you using the negation (!) in your for loop?
I think that what you wanted is:
for(int i=0; i<classes.size(); i++){
if(classes.get(i).contains("yago")){
classes.remove(i);
}
}
The problem with this approach is that when you remove an element from the list you change it's size. You could instead create an empty ArrayList and keep adding new elements to it if it does not obey the condition:
List<String> tmp = new ArrayList();
for(String token : classes){
if(!token.contains("yago")){
tmp.add(token);
}
}
for(String i : tmp){
System.out.println(i);
}
It might make since to iterate in reverse to avoid index problems. Try something like this:
for(int i=classes.size()-1; i>=0; i--)
{
//get a string from list
String s = classes.get(i);
if(!s.contains("yago"))
{
//if the string does not contain yago, remove it
classes.remove(i);
}
}

I want to get a specific combination of permutation?

I want to get specific combination of permutation of string like alphabet. To understand me, I'll show you the code that I using:
public class PermutationExample {
public static List<String> getPermutation(String input) {
List<String> collection = null;
if (input.length() == 1) {
collection = new ArrayList<String>();
collection.add(input);
return collection;
} else {
collection = getPermutation(input.substring(1));
Character first = input.charAt(0);
List<String> result = new ArrayList<String>();
for (String str : collection) {
for (int i = 0; i < str.length(); i++) {
String item = str.substring(0, i) + first
+ str.substring(i);
result.add(item);
}
String item = str.concat(first.toString());
result.add(item);
}
return result;
}
}
public static void main(String[] args) {
System.out.println(PermutationExample.getPermutation("ABCD"));
}
}
This code works well and i can get every combination, I can take it from the list, if I need 5-th element, I can receive it. But if the string is the alphabet ... , didn't works, it's too big. What I have to do, to get the specific element like 1221-th from all 26! combinations ?
I solved a similar problem a while ago, only in python.
If what you need is simply the n-th permutation, then you can do a lot better then generating every permutation and returning the n-th, if you try to think about generating only the permutation you need.
You can do this "simply" by figuring out what should be the element in front for the number of permutations you want, and then what should be the remaining of the elements recursively.
Assume a collection of values [0, ... ,X], for any values such that col[n] < col[n+1]
For N elements, there are N! possible permutations, the case when the collection will be perfectly reversed.
We will see the change in the head of the collection after each (N-1)! permutations, so if n < (N-1)!, the head is the head. You then have a remaining number of permutations, and you can apply the same logic recursively.
Does this help? I know it's fairly high level and you'll have to think a bit about it, but maybe it'll get you on the right track.

How to avoid java.util.ConcurrentModificationException when iterating through and removing elements from an ArrayList

I have an ArrayList that I want to iterate over. While iterating over it I have to remove elements at the same time. Obviously this throws a java.util.ConcurrentModificationException.
What is the best practice to handle this problem? Should I clone the list first?
I remove the elements not in the loop itself but another part of the code.
My code looks like this:
public class Test() {
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff() {
for (A a : abc)
a.doSomething();
}
public void removeA(A a) {
abc.remove(a);
}
}
a.doSomething might call Test.removeA();
Two options:
Create a list of values you wish to remove, adding to that list within the loop, then call originalList.removeAll(valuesToRemove) at the end
Use the remove() method on the iterator itself. Note that this means you can't use the enhanced for loop.
As an example of the second option, removing any strings with a length greater than 5 from a list:
List<String> list = new ArrayList<String>();
...
for (Iterator<String> iterator = list.iterator(); iterator.hasNext(); ) {
String value = iterator.next();
if (value.length() > 5) {
iterator.remove();
}
}
From the JavaDocs of the ArrayList
The iterators returned by this class's iterator and listIterator
methods are fail-fast: if the list is structurally modified at any
time after the iterator is created, in any way except through the
iterator's own remove or add methods, the iterator will throw a
ConcurrentModificationException.
You are trying to remove value from list in advanced "for loop", which is not possible, even if you apply any trick (which you did in your code).
Better way is to code iterator level as other advised here.
I wonder how people have not suggested traditional for loop approach.
for( int i = 0; i < lStringList.size(); i++ )
{
String lValue = lStringList.get( i );
if(lValue.equals("_Not_Required"))
{
lStringList.remove(lValue);
i--;
}
}
This works as well.
In Java 8 you can use the Collection Interface and do this by calling the removeIf method:
yourList.removeIf((A a) -> a.value == 2);
More information can be found here
You should really just iterate back the array in the traditional way
Every time you remove an element from the list, the elements after will be push forward. As long as you don't change elements other than the iterating one, the following code should work.
public class Test(){
private ArrayList<A> abc = new ArrayList<A>();
public void doStuff(){
for(int i = (abc.size() - 1); i >= 0; i--)
abc.get(i).doSomething();
}
public void removeA(A a){
abc.remove(a);
}
}
While iterating the list, if you want to remove the element is possible. Let see below my examples,
ArrayList<String> names = new ArrayList<String>();
names.add("abc");
names.add("def");
names.add("ghi");
names.add("xyz");
I have the above names of Array list. And i want to remove the "def" name from the above list,
for(String name : names){
if(name.equals("def")){
names.remove("def");
}
}
The above code throws the ConcurrentModificationException exception because you are modifying the list while iterating.
So, to remove the "def" name from Arraylist by doing this way,
Iterator<String> itr = names.iterator();
while(itr.hasNext()){
String name = itr.next();
if(name.equals("def")){
itr.remove();
}
}
The above code, through iterator we can remove the "def" name from the Arraylist and try to print the array, you would be see the below output.
Output : [abc, ghi, xyz]
Do the loop in the normal way, the java.util.ConcurrentModificationException is an error related to the elements that are accessed.
So try:
for(int i = 0; i < list.size(); i++){
lista.get(i).action();
}
Here is an example where I use a different list to add the objects for removal, then afterwards I use stream.foreach to remove elements from original list :
private ObservableList<CustomerTableEntry> customersTableViewItems = FXCollections.observableArrayList();
...
private void removeOutdatedRowsElementsFromCustomerView()
{
ObjectProperty<TimeStamp> currentTimestamp = new SimpleObjectProperty<>(TimeStamp.getCurrentTime());
long diff;
long diffSeconds;
List<Object> objectsToRemove = new ArrayList<>();
for(CustomerTableEntry item: customersTableViewItems) {
diff = currentTimestamp.getValue().getTime() - item.timestamp.getValue().getTime();
diffSeconds = diff / 1000 % 60;
if(diffSeconds > 10) {
// Element has been idle for too long, meaning no communication, hence remove it
System.out.printf("- Idle element [%s] - will be removed\n", item.getUserName());
objectsToRemove.add(item);
}
}
objectsToRemove.stream().forEach(o -> customersTableViewItems.remove(o));
}
One option is to modify the removeA method to this -
public void removeA(A a,Iterator<A> iterator) {
iterator.remove(a);
}
But this would mean your doSomething() should be able to pass the iterator to the remove method. Not a very good idea.
Can you do this in two step approach :
In the first loop when you iterate over the list , instead of removing the selected elements , mark them as to be deleted. For this , you may simply copy these elements ( shallow copy ) into another List.
Then , once your iteration is done , simply do a removeAll from the first list all elements in the second list.
In my case, the accepted answer is not working, It stops Exception but it causes some inconsistency in my List. The following solution is perfectly working for me.
List<String> list = new ArrayList<>();
List<String> itemsToRemove = new ArrayList<>();
for (String value: list) {
if (value.length() > 5) { // your condition
itemsToRemove.add(value);
}
}
list.removeAll(itemsToRemove);
In this code, I have added the items to remove, in another list and then used list.removeAll method to remove all required items.
Instead of using For each loop, use normal for loop. for example,the below code removes all the element in the array list without giving java.util.ConcurrentModificationException. You can modify the condition in the loop according to your use case.
for(int i=0; i<abc.size(); i++) {
e.remove(i);
}
Sometimes old school is best. Just go for a simple for loop but make sure you start at the end of the list otherwise as you remove items you will get out of sync with your index.
List<String> list = new ArrayList<>();
for (int i = list.size() - 1; i >= 0; i--) {
if ("removeMe".equals(list.get(i))) {
list.remove(i);
}
}
You can also use CopyOnWriteArrayList instead of an ArrayList. This is the latest recommended approach by from JDK 1.5 onwards.
Do somehting simple like this:
for (Object object: (ArrayList<String>) list.clone()) {
list.remove(object);
}
An alternative Java 8 solution using stream:
theList = theList.stream()
.filter(element -> !shouldBeRemoved(element))
.collect(Collectors.toList());
In Java 7 you can use Guava instead:
theList = FluentIterable.from(theList)
.filter(new Predicate<String>() {
#Override
public boolean apply(String element) {
return !shouldBeRemoved(element);
}
})
.toImmutableList();
Note, that the Guava example results in an immutable list which may or may not be what you want.
for (A a : new ArrayList<>(abc)) {
a.doSomething();
abc.remove(a);
}
"Should I clone the list first?"
That will be the easiest solution, remove from the clone, and copy the clone back after removal.
An example from my rummikub game:
SuppressWarnings("unchecked")
public void removeStones() {
ArrayList<Stone> clone = (ArrayList<Stone>) stones.clone();
// remove the stones moved to the table
for (Stone stone : stones) {
if (stone.isOnTable()) {
clone.remove(stone);
}
}
stones = (ArrayList<Stone>) clone.clone();
sortStones();
}
I arrive late I know but I answer this because I think this solution is simple and elegant:
List<String> listFixed = new ArrayList<String>();
List<String> dynamicList = new ArrayList<String>();
public void fillingList() {
listFixed.add("Andrea");
listFixed.add("Susana");
listFixed.add("Oscar");
listFixed.add("Valeria");
listFixed.add("Kathy");
listFixed.add("Laura");
listFixed.add("Ana");
listFixed.add("Becker");
listFixed.add("Abraham");
dynamicList.addAll(listFixed);
}
public void updatingListFixed() {
for (String newList : dynamicList) {
if (!listFixed.contains(newList)) {
listFixed.add(newList);
}
}
//this is for add elements if you want eraser also
String removeRegister="";
for (String fixedList : listFixed) {
if (!dynamicList.contains(fixedList)) {
removeResgister = fixedList;
}
}
fixedList.remove(removeRegister);
}
All this is for updating from one list to other and you can make all from just one list
and in method updating you check both list and can eraser or add elements betwen list.
This means both list always it same size
Use Iterator instead of Array List
Have a set be converted to iterator with type match
And move to the next element and remove
Iterator<Insured> itr = insuredSet.iterator();
while (itr.hasNext()) {
itr.next();
itr.remove();
}
Moving to the next is important here as it should take the index to remove element.
List<String> list1 = new ArrayList<>();
list1.addAll(OriginalList);
List<String> list2 = new ArrayList<>();
list2.addAll(OriginalList);
This is also an option.
If your goal is to remove all elements from the list, you can iterate over each item, and then call:
list.clear()
What about of
import java.util.Collections;
List<A> abc = Collections.synchronizedList(new ArrayList<>());
ERROR
There was a mistake when I added to the same list from where I took elements:
fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
for (i in this) {
this.add(_fun(i)) <--- ERROR
}
return this <--- ERROR
}
DECISION
Works great when adding to a new list:
fun <T> MutableList<T>.mathList(_fun: (T) -> T): MutableList<T> {
val newList = mutableListOf<T>() <--- DECISION
for (i in this) {
newList.add(_fun(i)) <--- DECISION
}
return newList <--- DECISION
}
Just add a break after your ArrayList.remove(A) statement

Categories