I'm developing an Android app where I get a List of names (Strings) from a SQLite database. Then, I show them on a List of Cardviews.
I'm also given a substring, so I'd like to check if any of the elements of the original List contains that substring on it.
I'm having problems using LIKE in the SQLite query, so I've just fixed it with a try{ } catch (Exception e) { }, but I don't feel so comfortable with it.
Anyway, since I originally have all of the names stored in the List of Strings, I don't really need to fecth the new ones again from the database, I can just search them on the original List of Strings. But I don't know how.
For example, let's say the List of String has this 5 elements:
Hello
Wall
Helicopter
Chair
Hell
And I'm given the substring Hel. I should get the Hello, Helicopter and Hell strings, since all of them contain the substring Hel.
Any ideas on how to achieve this goal?
It's not that I want to fix it this way. I sincerely would like to know what's the most efficient, if retrieveing the data again from the database, or search it from the List of Strings.
EDIT: I originally said that I was using the CONTAINS query, but I missed the word. I just meant the LIKE query. I'm actually using it, and it works fine but I don't really know what's the most efficient in my case.
Thanks in advance.
Here is my suggestion
public boolean isSubstring(String str, String key) {
if(key.length() > str.length()) return false;
for(int i = 0; i <= str.length() - key.length(); i++) {
if( key.equals(str.substring(i, i + key.length())) ) return true;
}
return false;
}
public List<String> findStings(List<String> list, String key) {
List<String> newList = new ArrayList<>();
for(int i = 0; i < list.size(); i++) {
if(isSubstring(list.get(i), key)) {
newList.add(list.get(i));
}
}
return newList;
}
If you are working with Java 8 you can replace the for-loop of the second method as:
for(String str: list) {
if(isSubstring(str, key)) newList.add(str);
}
or simply as:
list.stream().filter((str) -> (isSubstring(str, key))).forEach((str) -> { newList.add(str); });
If you're using Java 8:
List<String> filteredList = myList.stream().filter(s -> s.contains("Hel")).collect(Collectors.toList());
If you're using anything earlier, use a for each loop:
List<String> filteredList = new ArrayList<String>();
for(String s : myList)
if(s.contains("Hel")
filteredList.add(s);
Related
I'm creating a java scraping program using selenium and inserting the data into a database. I'm actively looking to improve my skillset but I don't find instructional videos too helpful since I lose interest, but I really enjoy learning through doing. This code below works as needed, but it looks really really ugly and I feel there must be a better/cleaner solution. For reference it builds a comma separated string with data such as "Value1", or "Value1, Value2", etc depending on the keyword count. My original logic was outputting ", Value1, Value2" which is why I added the "if (x ==0)" logic. I have a lot of methods that are just sloppy like this, so any pointers for improving my code is appreciated, thanks!
ArrayList<String> keywords = new ArrayList<String>();
keywords = keywordChecker(title);
for (int x = 0; x < keywords.size(); x++) {
String list = keywords.get(x);
if (x == 0) {
keywordListBuilder = list;
} else if (x > 0) {
keywordListBuilder = keywordListBuilder + ", " + list;
}
}
keywordValues.add(keywordListBuilder);
public ArrayList<String> keywordChecker(String title) {
ArrayList<String> keywordList = new ArrayList<String>();
String keyword1 = "";
String keyword2 = "";
String keyword3 = "";
String[] keywordTextCombinations = { "Value1", "Value2", "Value3", [imagine a list of 20 items]};
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())) {
keyword1 = keywordTextCombinations[i];
keywordList.add(keyword1);
break;
}
}
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword1.toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword2.toLowerCase())) {
keyword2 = keywordTextCombinations[i];
keywordList.add(keyword2);
break;
}
}
for (int i = 0; i < keywordTextCombinations.length; i++) {
if (title.toLowerCase().contains(keywordTextCombinations[i].toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword1.toLowerCase())
&& !keywordTextCombinations[i].toLowerCase().equals(keyword2.toLowerCase())) {
keyword3 = keywordTextCombinations[i];
keywordList.add(keyword3);
break;
}
}
return keywordList;
}
ArrayList<String> keywords = new ArrayList<String>();
keywords = keywordChecker(title);
This will:
Create a new variable, named keywords, that can point at arraylists.
Makes a new arraylist object.
Assigns the reference to this newly created object to the keywords variable.
Then tosses that reference away and makes that created object instant garbage, as you then immediately assign some other reference to it.
In other words, that new ArrayList<String>(); does nothing whatsoever but waste time and space. Get rid of it. Let's also be like other java coders and use the most general type that we're interested in. For beginners, that basically means, 'the variable should be of type List, not ArrayList. It's good to write code in similar style to other java coders; makes it easier to read their code and it makes it easier for them to read your code.
List<String> keywords = keywordChecker(title);
for (int x = 0; x < keywords.size(); x++) {
String list = keywords.get(x);
if (x == 0) {
keywordListBuilder = list;
} else if (x > 0) {
keywordListBuilder = keywordListBuilder + ", " + list;
}
}
keywordValues.add(keywordListBuilder);
You're getting a single keyword and you call this list? Names are important. When they lie, your code becomes unreadable.
You're turning a list of strings into a single string with all the values, separated by a comma. That sounds like a common job. When something sounds common enough, search the web. You'll usually find that there's a one-liner. So it is here:
keywordValues.add(String.join(", ", keywords));
Oof, that's way less code.
The keywordChecker method
It helps to document code, especially when asking for help. Evidently, this method is to scan the provided title variable, and search for any of a list of keywords, then it is to return each matching keyword. However, you've limited to return at most 3. I assume you didn't want that. But if you do, I'll show you how, with a one-liner of course.
String keyword1 = "";
String keyword2 = "";
String keyword3 = "";
When you start naming variables like this, stop. There's no way that's correct. Think for a moment. You're already using them, you know how to do this properly: Lists. Once you use a list, this becomes near trivial. Also, method names should generally be a verb; common java style. Let's also make constants, well, constant. Let's also avoid arrays, they are unwieldy and annoying.
private static final List<String> KEYWORDS = List.of("Value1", "Value2", "Value3", [imagine a list of 20 items]);
public List<String> findMatchingKeywords(String title) {
var out = new ArrayList<String>();
String lowercased = title.toLowerCase();
for (String keyword : KEYWORDS) {
if (lowercased.contains(keyword.toLowerCase()) out.add(keyword);
}
return out;
}
That eliminated a ton of lines, that's nice. If you want to return no more than 3 keywords at most... all you need to do is abort looping when you're 'full'. As last line within the for loop:
if (out.length() == 3) break;
Putting it all together:
keywordValues.add(String.join(", ", findMatchingKeywords(title)));
...
private static final List<String> KEYWORDS = List.of("Value1", "Value2", "Value3", [imagine a list of 20 items]);
public List<String> findMatchingKeywords(String title) {
var out = new ArrayList<String>();
String lowercased = title.toLowerCase();
for (String keyword : KEYWORDS) {
if (lowercased.contains(keyword.toLowerCase()) {
out.add(keyword);
if (out.length() == 3) break;
}
}
return out;
}
You can try to do everything in one for loop. Also, I recommend that you use a HashSet since you are comparing elements. A HashSet cannot contain duplicate elements, so if you try to add an element that already exists it doesn't do it and it returns false (Yes, the add function in HashSet returns a boolean).
I'm trying to answer this question:
Program the method findIngredients. This method takes in a String called
foodInStock, and an ArrayList of Strings called ingredients. The method should return an
ArrayList of ingredients that were not found in foodInStock.
for example if:
foodInStock = “tomatopotatocornturkeycarrotstuffing”
ingredients = {“potato”, “corn”, “salt”, “chicken”, “turkey”}
returns {“salt”, “chicken”}
I tried writing some code but for some reason everything is getting removed when I use the above example on my program. Where did my program go wrong?
Here's my code:
public static ArrayList<String> findIngredients(String foodInStock, ArrayList<String> ingredients){
ArrayList<String> ingredientsNotFound = new ArrayList<String>();
int i = 0;
for (; i < ingredients.size(); i++) {
for (int x = 0; x < foodInStock.length()-(ingredients.get(i).length())+1; x++) {
if (ingredients.get(i) == foodInStock.substring(x, (x + ingredients.get(i).length()))) {
ingredients.remove(i);
i = 0;
break;
}
}
}
ingredients = ingredientsNotFound;
return ingredientsNotFound;
}
I think there are two main things to cover here.
First, the way to build the final result. You are currently removing items from the original input; a better strategy is to add items to a new list (partially because it's simpler to think about and partially because you generally don't want to modify a list while iterating over it).
You also are, probably accidentally, overwriting your list with an empty list at the end.
Second, the way to determine whether or not the ingredient is in the string input. Rather than looping over the whole string and inspecting substrings, you can instead use the indexOf() method to see whether or not the string includes the current item.
public static ArrayList<String> findIngredients(String foodInStock, ArrayList<String> ingredients) {
ArrayList<String> results = new ArrayList<>();
for (String ingredient : ingredients) {
if (foodInStock.indexOf(ingredient) == -1) {
results.add(ingredient);
}
}
return results;
}
Here we initialize a new list for the results. We then loop over every individual ingredient in the input list, and ask whether or not that ingredient is present in the string input. When it is not (indexOf() returns -1), we add it to the results list. At the end, the results contains every ingredient not found.
Let say I have an array list with names and the names are stored like this...
John(2),
Bob(anytext),
Rick
I'm trying to iterate over my array list and check for "(" basically and just take the rest of the string behind it and return that as a string, and null if nothing there. I've seen methods to do similar things but I can't seem to find something to just return the rest of the string if it finds the "("
for(int i=0; i<list.size(); i++) {
String s = list.get(i);
int x = s.indexOf('(');
if(x==-1) break;
return s.substring(x+1);
}
Pass the strings you want to check to a method that does something like this:
if(str.contains("(")){
return str.substring(str.indexOf("("));
}else{
return null;
}
Java 8 version
List<String> list = Arrays.asList("John(2)", "Bob(anytext)", "Rick");
String result = list.stream()
.filter(x -> x.contains("("))
.findFirst()
.map(x -> x.substring(x.indexOf("(")))
.orElse(null);
I am currently working on a project where I need to check an arraylist for a certain string and if that condition is met, replace it with the new string.
I will only show the relevant code but basically what happened before is a long string is read in, split into groups of three, then those strings populate an array. I need to find and replace those values in the array, and then print them out. Here is the method that populates the arraylist:
private static ArrayList<String> splitText(String text)
{
ArrayList<String> DNAsplit = new ArrayList<String>();
for (int i = 0; i < text.length(); i += 3)
{
DNAsplit.add(text.substring(i, Math.min(i + 3, text.length())));
}
return DNAsplit;
}
How would I search this arraylist for multiple strings (Here's an example aminoAcids = aminoAcids.replaceAll ("TAT", "Y");) and then print the new values out.
Any help is greatly appreciated.
In Java 8
list.replaceAll(s-> s.replace("TAT", "Y"));
There is no such "replace all" method on a list. You need to apply the replacement element-wise; the only difference vs doing this on a single string is that you need to get the value out of the list, and set the new value back into the list:
ListIterator<String> it = DNAsplit.listIterator();
while (it.hasNext()) {
// Get from the list.
String current = it.next();
// Apply the transformation.
String newValue = current.replace("TAT", "Y");
// Set back into the list.
it.set(newValue);
}
And if you want to print the new values out:
System.out.println(DNAsplit);
Why dont you create a hashmap that has a key-value and use it during the load time to populate this list instead of revising it later ?
Map<String,String> dnaMap = new HashMap<String,String>() ;
dnaMap.push("X","XXX");
.
.
.
dnaMap.push("Z","ZZZ");
And use it like below :
//Use the hash map to lookup the temp key
temp= text.substring(i, Math.min(i + 3, text.length()));
DNAsplit.add(dnaMap.get(temp));
This function loops through a dictionary (allWords) and uses the
getKey function to generate a key. wordListMap is a HashMap> so I need to loop through and put the key and and a List. If there is not a list I put one if there is I just need to append the next dictionary word. This is where I need help. I just can't figure out the syntax to simply append the next word to the list that is already there. Any Help would be appreciated.
public static void constructWordListMap() {
wordListMap = new HashMap<>();
for (String w : allWords) {
int key = getKey(w);
if (isValidWord(w) && !wordListMap.containsKey(key)) {
List list = new ArrayList();
list.add(w);
wordListMap.put(key, list);
} else if (isValidWord(w) && wordListMap.containsKey(key)) {
wordListMap.put(key, wordListMap.get(key).add(w));
}
}
}
map.get(key).add(value)
Simple as that.
So I've gathered that you want to, given HashMap<Integer, List<String>>, you'd like to:
create a List object
add String objects to said List
add that List object as a value to be paired with a previously generated key (type Integer)
To do so, you'd want to first generate the key
Integer myKey = getKey(w);
Then, you'd enter a loop and add to a List object
List<String> myList = new List<String>;
for(int i = 0; i < intendedListLength; i++) {
String myEntry = //wherever you get your string from
myList.add(myEntry);
}
Lastly, you'd add the List to the HashMap
myHash.put(myKey, myList);
Leave any questions in the comments.
else if (isValidWord(w) && wordListMap.containsKey(key)) {
wordListMap.put(key, wordListMap.get(key).add(w));
}
If you want to add a new value to your list, you need to retrieve that list first. In the code above, you are putting the return value of add into the table (which is a boolean), and that is not what you want.
Instead, you will want to do as Paul said:
else if (isValidWord(w) && wordListMap.containsKey(key)) {
wordListMap.get(key).add(w);
}
The reason this works is because you already added an ArrayList to the table earlier. Here, you are getting that ArrayList, and adding a new value to it.