How to split element in an ArrayList in multidimensional arrayList - java

I have the following:
[[Statistics (pH)], [ Upright Normal Recumbent Normal Total]]
I want to split the first element of the second element on whitespace so that I end up with:
[[Statistics (pH)], [Upright,Normal,Recumbent,Normal,Total]]
My code so far:
for (ArrayList<List<String>> row2 : StatspH) {
row2.get(1).get(0).split("\\s");
}
but nothing happens

Java Strings are immutable, so you need to store the return value of split("\\s") in the correct List.
I recommend something like
for (ArrayList<List<String>> row2 : StatspH) {
List<String> stats = row2.get(1);
// remove() returns the object that was removed
String allStats = stats.remove(0);
Collections.addAll(stats, allStats.split("\\s"));
}
Note that we're removing the original string first, then adding all of the 'split' values.

Related

Adding a String to a StringList while it is part of a hashmap value

Say I have Map<List<String>, List<String>> whatComesNext,
And while in a for loop, for every iteration I want to add the nth element of List<String> text to the value of whatComesNext. Why can I not perform whatComesNext.put(key, whatComesNext.get(key).add(text.get(n)))? The idea would be to retrieve the value from its respective key in the hashmap and add my desired String to it. This is assuming that every key in the hashmap has a value.
Below is my full code:
static void learnFromText(Map<List<String>, List<String>> whatComesNext, List<String> text) {
for (int i=0; i<=text.size()-3; i++) {
if (whatComesNext.containsKey(Arrays.asList(text.get(i),text.get(i+1)))==false) {
whatComesNext.put(Arrays.asList(text.get(i),text.get(i+1)), Arrays.asList(""));
}
whatComesNext.put(Arrays.asList(text.get(i),text.get(i+1)), whatComesNext.get(Arrays.asList(text.get(i),text.get(i+1))).add(text.get(i+2)));
}
}
The Arrays.asList() looks complicated, but it's because I was getting null maps when trying to intialize my own String Lists to try and hold my keys and values, which someone told me was because I was repeatedly clearing the lists that the keys & values were assigned to, leaving them null. I thought I'd solve that problem by referring directly to the original List<String> text, because that remains unchanged. The idea is to first check if a key is not present in the map, and if so assign it an empty List as a value, and then add a String from text to the value of the map.
The error I get when running the code is Error: incompatible types: boolean cannot be converted to java.util.List<java.lang.String> in the line whatComesNext.get(Arrays.asList(text.get(i),text.get(i+1))).add(text.get(i+2)));. I don't understand where this could go wrong, because I don't see which method is returning a boolean.
The error comes from the fact that List.add(Object o) returns a boolean and not the List itself. The Map is declared to contain instances of List<String> as value. If you simply want to add a value to a list, just retrieve it from the map and call add on it. Check the result of the get-process for null and create a new list and put it into the Map if that's the case
I can see a couple of other problems as well:
You call Arrays.asList(...) multiple times creating multiple lists with the same elements. This is a major performance issue and you're just lucky, that the returned list is actually implementing equals, so that your logic is actually working (I expected that to be the problem of your "doesn't work"-description before you updated it.
If the key doesn't exist, you're creating a List containing an empty text. If that should be an empty list, that's not what you're doing and you might run into problems later on, when you work with text-values (that is the empty text as first element) that weren't part of the original input values.
Without changing the type of the key of the Map a - in my eyes - better implementation would look like this:
static void learnFromText(Map<List<String> whatComesNext, List<String>, List<String> text) {
for (int i=0; i<= text.size() - 3; i++) {
List<String> listKey = text.subList(i, i+2);
List<String> value = whatComesNext.get(listKey);
if (value == null) {
value = new ArrayList<>();
whatComesNext.put(listKey, value);
}
value.add(text.get(i+2)));
}
}
The calculation of the list for the keys happens only once, increasing performance and reducing the need of resources. And I think it's more readable that way as well.
The .add() method returns a boolean, your parenthesis are misplaced, replace your last line with this one:
whatComesNext.put(Arrays.asList(text.get(i),text.get(i+1)), whatComesNext.get(Arrays.asList(text.get(i),text.get(i+1)))).add(text.get(i+2));

Converting List<List<String>> to array

I have elements that is declared in a list variable such as:
List<List<String>> textList = new ArrayList<>();
The elements are added such as:
textList.add(Arrays.asList(p)); //adding elements
The only way I could output the elements inside the variable is by using:
for(List<String> s: textList){
System.out.println(s); }
which output elements like this:
[He is a boy.]
[He likes apple.]
[She is a girl.]
Now, I would like to store them in an array so that the elements will look like this when outputted.
[He is a boy., He likes apple., She is a girl.]
I've tried
String[] textArr = new String[textList.size()];
textArr = textList.toArray(textArr);
for(String s : textArr){
System.out.println(s);}
but I got an error about:
Exception in thread "main" java.lang.ArrayStoreException
at java.lang.System.arraycopy(Native Method)
at java.util.Arrays.copyOf(Arrays.java:3213)
at java.util.ArrayList.toArray(ArrayList.java:407)
So, how do I convert the elements inside a list into array using the proper way. Thanks!
Your problem is that you are not storing Strings in your list textList.
textList.add(Arrays.asList(p));
As the type says, you have a List of List of String here.
So you can't take the elements of that list and assume they are Strings. Because they aren't! The error message tells you that: toArray() wants strings it can put into that array of strings, but you give it a List of List of String!
But thing is: what you are describing here doesn't make sense in the first place. Printing strings shouldn't care if strings are in an array or a List.
What I mean is: when you manually iterate a List or an array to print its content, then it absolutely doesn't matter if you iterate a List or an array. The code is even the same:
for (String someString : someCollection) {
System.out.println(someString);
}
someCollection can be both: array or List!
In other words: the idea to turn data that is nicely stored within Lists into arrays for printing simply doesn't make any sense. To the contrary: you are probably calling toString() on your List object, and the result of that ... isn't 100% what you want. But I guarantee you: calling toString() on some array will result in something you totally will not want.
Long story short: forget about converting to Arrays; simply iterate your List of List of Strings and use a StringBuilder to collect the content of that collection the way you want to see it (you simply append those [ ] chars to that builder in those places you want them to see).
(if you insist on that conversion to array, the key point there to understand is that only a List of String can be turned into an array of string. So a List of List ... doesnt work that easy).
Using streams and flatMap, you can do this:
List<List<String>> list = ...;
String[] strings = list.stream().flatMap(l -> l.stream()).collect(Collectors.toList()).toArray(new String[0]);
This is equivalent to using a loop (You can use two nested for loops as suggested in the comments instead by replacing the addAll, but why?):
List<List<String>> list = ...;
List<String> stringList = new ArrayList<>();
for (List<String> l : list)
stringList.addAll(l);
String[] strings = list.toArray(new String[stringList.size()]);
You can use Iterator in order to go over every element of the list, instance of the for each statement (I personally like the iterators more). The code you could use would be something like
//Your list
List<List<String>> textList = new ArrayList<>();
//The iterators
Iterator<List<String>> itList = textList.iterator();
Iterator<String> itString;
//The string to store the phrases
String s[] = new String[textList.size()];
int i =0;
//First loop, this seeks on every list of lists
while(itList.hasNext()){
//Getting the iterator of strings
itString = itList.next().iterator();
s[i] = "";
//2nd loop, it seeks on every List of string
while(itString.hasNext()){
s[i] = s[i].concat(itString.next());
}
s[i] = s[i].concat(".");
i++;
}

Remove a String Item from a List of Strings

How do I remove a specific string from a List that contains Strings....
As in:
ArrayList<String> myStrings = new ArrayList<>();
myStrings.add("Alpha");
myStrings.add("Beta");
myStrings.add("Gama");
. //The order can be random
.
.
.
Now , I only have the list myStrings and I don't know which String is at which index. But I know, that I want to display all the strings after removing say "Alpha".
To Summarize , How can I get the strings from a String array after removing a String that I know that array contains , but don't know its index/position.
Use remove :
myStrings.remove("Alpha");
Note that this would only remove the first occurrence of "Alpha" from your list.
boolean remove(Object o)
The above method of ArrayList class will remove the first occurence of Object o from the list.
You can do:
myStrings.remove("Alpha");
It will return true if the ArrayList contained the specified element.
Do you have duplicates in the list of String that you also wish to remove?
If so, you can convert the list of String into a set of String. Then, you can remove strings from the set efficiently, convert it back into a map.
// converting to set will remove duplicates
final Set<String> uniqueStrSet = new HashSet<String>(listOfString);
// remove string from set
uniqueStrSet.remove(strToRemove);
// convert set back to list
list = new ArrayList<String>(uniqueStrSet);
if this not work
myStrings.remove("Alpha");
try this it works fine with me
int pos = myStrings.indexOf("Alpha");//Getting string position
myStrings.remove(pos);

How to loop over a list in Java in a minimum step

I have the following for loop, where the StringList is
List<String> stringList= new ArrayList<String>();
for (String elementList : stringList)
{
if (elementList =="string1")
{
Key=1;
}
else if (elementList =="string2")
{
Key=0;
}
// do some code here
}
If the (stringList) includes 20,000 string words. The repeating of the words "string1" and "string2" is 10,000 for each in (stringList). it takes time to check every word in the for loop.
How can we make the for loop iterate only two times because there are only two types of words which are "string1" and "string2" regardless of it's repeating in the (stringList)
As i said you should use method equals for comparing two strings. And also i think you can use method contains() to check if your list contains some strings
contains(Object o) Returns true if this list contains the specified
element.
if (stringList.contains("string1"))
Key = 1;
if (stringList.contains("string2"))
key = 2;

For-Each and Pointers in Java [duplicate]

This question already has answers here:
Why does the foreach statement not change the element value?
(6 answers)
Closed 5 years ago.
Ok, so I'm tyring to iterate through an ArrayList and remove a specefic element. However, I am having some trouble using the For-Each like structure. When I run the following code:
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for(String t : arr)
{
t = " some other value "; //hoping this would change the actual array
}
for(String t : arr)
{
System.out.println(t); //however, I still get the same array here
}
My question in, how can I make 't' a pointer to 'arr' so that I am able to change the values in a for-each loop? I know I could loop through the ArrayList using a different structure, but this one looks so clean and readable, it would just be nice to be able to make 't' a pointer.
All comments are appreciated! Even if you say I should just suck it up and use a different construct.
I think the best approach may be to use a for loop.
ArrayList<String> arr = new ArrayList<String>();
for (int i = 0; i < arr.size(); i++) {
String t = arr.get(i);
if (// your condition is met) {
arr.set(i, "your new value");
}
}
The problem is that you're trying to change the loop-scoped reference t to let it point to a new String instance. This ain't going to work. It does not refer the actual entry in the arraylist. You need to change the actual value of the reference. If String was mutable and provided a fictive set() method for that, you could in theory do
for (String t : arr) {
t.set("some other value");
}
or so, but that's not possible as it is immutable. Better get a handle of the entrypoint in the array itself using the normal for loop:
for (int i = 0; i < arr.size(); i++) {
arr.set(i, "some other value");
}
If you insist in using the enhanced for loop, then you need to replace String by StringBuilder, which is mutable:
for (StringBuilder t : arr) {
t.delete(0, t.length()).append("some other value");
}
Remember, Java is pass-by-value, not pass-by-reference.
For-each doesn't give you an index pointer, so you just can't use it to change an immutable value.
Either use a for-loop with an index or use a mutable type (like StringBuffer, not String)
An array of objects (like strings) in Java is a contiguous block containing an ordered series of references. So, when you have an array of 4 strings, what you really have is 4 references stored IN the array, and 4 string objects that are outside of the array but are referenced by its 4 elements.
What the for-each construct in Java does is create a local variable and, for each iteration, copy into that local variable the reference from the array cell that corresponds to that iteration. When you set the loop variable (t = " some other value") you are putting a reference to a new string, "some other value", into the local variable t, not into the array.
The contrasts with some other languages (like Perl) where the loop variable acts like an alias to the array/list element itself.
Your code is re-written by the compiler as something like this:
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for (final Iterator <String> i = arr.iterator(); i.hasNext();) {
String t;
t = i.next();
t = " some other value "; // just changes where t is pointing
}
To do what you want you would have to write the for loop like this:
for (final ListIterator<String> i = arr.iterator(); i.hasNext();) {
final String t;
t = i.next();
i.set("some other value");
}
Iterator does not have the set method, only ListIterator does.
Basically you want to remove the String t from the list arr. Just do a arr.remove(t) and you could be done. But you can't do it while iterating over the same list. You'll get an Exception if you try to modify the list this way.
You have two options:
clone your list, iterate through the clone and remove the 'specific' String from the original list
create a list for delete candidates, add all 'specific' Strings to that list and, after iterating through the original list, iterate through the wastebin and remove everything you've collected here from the original list.
Option 1 is the easist, the clone can be made like:
List<String> clone = new ArrayList<String>(arr);
You seem to misunderstand how objects/references work in Java, which is pretty fundamental to using the language effectively. However, this code here should do what you want (apologies for the lack of explanation):
ArrayList<String> arr = new ArrayList<String>();
//... fill with some values (doesn't really matter)
for(int i = 0; i < arr.size(); i++)
{
arr.set(i, " some other value "); // change the contents of the array
}
for(String t : arr)
{
System.out.println(t);
}
I believe, this is not related to immutable or mutable.
t = " some other value "; //hoping this would change the actual array
t does not hold the reference to actual object. Java copies the value from arraylist and puts that value into t so array list value does not get affect.
HTH
This has been answered well. Still here is my suggestion. The var t inside loop is only visible there. It will not be seen outside the loop. You could do t.set() if it was not String.
Use a StringBuffer rather than plain strings. This way the string within is mutable.
Strings are immutable. If you had a mutable type like StringBuilder/Buffer, you could change the string in your iteration. You do have references, remember.

Categories

Resources