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.
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 am trying to iterate through many arrays, two at a time. They contain upwards of ten-thousand entries each, including the source. In which I am trying to assign each word to either a noun, verb, adjective, or adverb.
I can't seem to figure a way to compare two arrays without writing an if else statement thousands of times.
I searched on Google and SO for similar issues. I couldn't find anything to move me forward.
package wcs;
import dictionaryReader.dicReader;
import sourceReader.sourceReader;
public class Assigner {
private static String source[], snArray[], svArray[], sadvArray[], sadjArray[];
private static String nArray[], vArray[], advArray[], adjArray[];
private static boolean finished = false;
public static void sourceAssign() {
sourceReader srcRead = new sourceReader();
//dicReader dic = new dicReader();
String[] nArray = dicReader.getnArray(), vArray = dicReader.getvArray(), advArray = dicReader.getAdvArray(),
adjArray = dicReader.getAdjArray();
String source[] = srcRead.getSource();
// Noun Store
for (int i = 0; i < source.length; i++) {
if (source[i] == dicReader.getnArray()[i]) {
source[i] = dicReader.getnArray()[i];
}else{
}
}
// Verb Store
// Adverb Store
// Adjective Store
}
}
Basically this is a simpler way to get a list of items that are in both Lists
// construct a list of item for first list
List<String> firstList = new ArrayList<>(Arrays.asList(new String[0])); // add items
//this function will only keep items in `firstList` if the value is in both lists
firstList.retainAll(Arrays.asList(new String[0]));
// iterate to do your work
for(String val:firstList) {
}
I am trying to find out if there is a possibility of returning the updated ArrayList after removing the specified element at the index in a single line so that I can pass it on to the recursive function.
Below is a snippet of my code which tries to generate all valid parenthesis combinations given n pairs of "()" brackets.
My concern is in the recursive function call "findAllCombinations" where after some validations I want to remove one character at each recursive call from the arrayList courceSet. However sourceSet.remove(index) returns a character. Instead I want to pass the updated list after removing the character in one line. Is it possible ?
Note : The line below is syntactically wrong and just used for better illustration.
findAllCombinations(sourceSet.remove(index), soFar + singleBracket, singleBracket); .
I did go through the official documentation but did not find any help.
Any help is appreciated, and thanks for your time.
public class GenerateParenthesis {
char singleBracket;
List<String> answerSet = new ArrayList<String>();
char[] repoSet = {'(',')'};
public List<String> generateParenthesis(int n) {
String soFar = "(";
List<Character> sourceSet = new ArrayList<Character>();
for(int i = 0;i<n;i++){
sourceSet.add('(');
sourceSet.add(')');
}
findAllCombinations(sourceSet,soFar,'(');
return answerSet;
}
public void findAllCombinations(List<Character> sourceSet,String soFar,Character toRemove){
if(sourceSet.isEmpty()){
answerSet.add(soFar); // append to a answer set list containing all combinations
return;
}
for(int i = 0;i<2;i++){
singleBracket = repoSet[i];
int index = sourceSet.indexOf(singleBracket);
if(index!=-1) {
findAllCombinations(sourceSet.remove(index), soFar + singleBracket, singleBracket);
}
}
}
public static void main(String args[]){
GenerateParenthesis gp = new GenerateParenthesis();
List<String> ans = new ArrayList<String>();
ans = gp.generateParenthesis(3);
}
}
ArrayList (likely to most List implementations) is a mutable data structure: calling remove you modify the list rather than returning a new list without the removed element.
If you want the latter behavior, the quick and easy way is to do a copy of the list.
// (inside the if...)
// pass the original list to the constructor to make a copy
List<Character> sourceSetCopy = new ArrayList<>(sourceSet);
// modify the copy
sourceSetCopy.remove(index);
// use the modified copy
findAllCombinations(sourceSetCopy, soFar + singleBracket, singleBracket);
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);
}
}
Hi community I have a question, I happen to have an array of objects loaded on startup, through that generate array another array of integers that contains your code, it appears that array of integers'm removing their values, what I want is to compare the list of integer array currently have with the array of objects, and remove all code object that whole array mentioned is found.
My code java:
private List<ValidColumnKey> columnCustomer;
private int[] selectedCustomer;
public void init(){
this.setColumnCustomer(new ArrayList<ValidColumnKey>());
this.getColumnCustomer().add(new ValidColumnKey(1, "Codigo", "code"));
this.getColumnCustomer().add(new ValidColumnKey(2, "Nombre", "name"));
this.getColumnCustomer().add(new ValidColumnKey(3, "Nombre Comercial", "comercialName"));
this.getColumnCustomer().add(new ValidColumnKey(4, "Estado", "isActive"));
this.setSelectedCustomer(new int [this.getColumnCustomer().size()]);
int i = 0;
for(ValidColumnKey column : this.getColumnCustomer()){
this.getSelectedCustomer()[i] = column.getCodigo();
i++;
}
}
I mean I would have my array of integers with codes removed, like this:
selectedCustomer = [1, 2, 3];
What I wanted was to remove from the list of objects that do not have codes in the array of integers, but it is not my code:
List<ValidColumnKey> auxRemoColumnKeys = new ArrayList<ValidColumnKey>();
for(ValidColumnKey column : this.getColumnCustomer()){
for(Integer codigo : this.getSelectedCustomer()){
if (column.getCodigo() != codigo) {
auxRemoColumnKeys.add(column);
break;
}
}
}
this.getColumnCustomer().remove(auxRemoColumnKeys);
I could guide the solution.
this.getColumnCustomer().remove(auxRemoColumnKeys);
This statement assumes you have a valid equals method for your class ValidColumnKey, which I suspect is probably not the case.
What you want to do is iterate with a Iterator. Some sample code could be like
Set<Integer> toRemoveCodes = new HashSet<Integer>(Arrays.asList(1, 2, 3));
for (Iterator<ValidColumnKey> it = this.getColumnCustomer().iterator(); it.hasNext(); ) {
ValidColumnKey curColumnKey = it.next();
Integer code = curColumnKey.codigo();
if (toRemoveCodes.contains(code)) {
it.remove();
}
}
There are multiple reasons your current attempt is failing. The first is that this line:
if (column.getCodigo() != codigo) {
Is testing for object equivalence between Integers, not value equavalence between ints. If you want to compare Integers, you have to use the equals method:
if (!column.getCodigo().equals(codigo)) {
However, if getCodigo returns an int and getSelectedCustomer returns an int[] then this line should be changed instead:
for(int codigo : this.getSelectedCustomer()){
Because you didn't need to use Integer in the first place.
Secondly, this line attempts to remove auxRemoColumnKeys itself so you probably mean removeAll:
this.getColumnCustomer().remove(auxRemoColumnKeys);
Lastly, your logic is generally flawed. It basically says "for each element in getColumnCustomer, if getCodigo is not equal to all of getSelectedCustomer remove it". I don't think that's what you've intended.
This is a modified loop that uses the same "add to a list and remove the list items" procedure but the logic will work:
List<ValidColumnKey> auxRemoColumnKeys = new ArrayList<ValidColumnKey>();
int[] selected = this.getSelectedCustomer();
for (ValidColumnKey column : this.getColumnCustomer()) {
int i = 0;
for ( ; i < selected.length; i++) {
/* note: if getCodigo returns an Integer change this check to
* "if (column.getCodigo().equals(selected[i])) {"
*/
if (column.getCodigo() == selected[i]) {
break;
}
}
/* this says "if the search loop did not break early" */
if (i == selected.length) {
auxRemoColumnKeys.add(column);
}
}
this.getColumnCustomer().removeAll(auxRemoColumnKeys);