I currently have this code that is fully functioning in Java. It takes a string, turns it into an array and removes all of the duplicates. I decided to use the string "a sailor went to sea sea sea to see what he could see see see but all that he could see see see was the bottom of the deep blue sea sea sea". I used this as it has a large number of duplicates.
To add to the code I would like to be able to get the positions of all the elements in the array, I believe the correct method is through nested loops but I am not sure how to accomplish this. If anyone has some guidance or even general ideas i would be great full.
Here is the current code:
static ArrayList<String> removeDuplicates(String[] list) {
// Store unique items in result.
ArrayList<String> result = new ArrayList<>();
// Record encountered Strings in HashSet.
HashSet<String> set = new HashSet<>();
// Loop over argument list.
for (String item : list) {
// If String is not in set, add it to the list and the set.
if (!set.contains(item)) {
result.add(item);
set.add(item);
}
}
return result;
}
public static void main(String[] args) {
String sea1 = "A sailor went to sea sea sea, to see what he could see see see, but all that he could see see see, was the bottom of the deep blue sea sea sea";
String sea2 = sea1.toLowerCase();
String sea3 = sea2.replaceAll("[\.:;,\"!\?]", " "); //remove punctuation + sets to lower case
String sea4 = sea3.replaceAll(" ", " ");
String sea5 = sea4.replaceAll(" ", ",");
String sea6 = sea5.replaceAll("'", " ");
String sea7 = sea6.replaceAll(" ", "");
System.out.println("Here is the string: " + sea7);
String[] sealist = sea7.split(",");
System.out.println("Here is the string 'end' with duplicates removed: ");
// Remove duplicates from ArrayList of Strings.
ArrayList<String> unique = removeDuplicates(sealist);
for (String element : unique) {
System.out.println("- " + element);
}
}
}
Your code is good, but if the order is critical, why not use a LinkedHashSet?
Add the elements to the linkedhashset, then to get them back in the order they were added, simply get the entries as toString(). You'll have a comma delimiting the returned words, but they can easily be removed. It will look like "[a,sailor,went,to,sea,see,what ...]"
static ArrayList<String> removeDuplicates(String[] list) {
// Record encountered Strings in HashSet.
LinkedHashSet<String> set = new LinkedHashSet<>();
// Loop over argument list.
for (String item : list) {
// Left this if statement in for clarity (!needed)
if (!set.contains(item)) {
set.add(item);
}
}
String result= set.toString();
return(result.split(",");
}
Related
I am struggling with removing spaces in an arraylist of strings.
Say the user input is as follows: "I walked my dog", my code outputs this:
[I, walked, my, dog]
I want it to have no spaces as such:
[I,walked,my,dog]
I tried to remove whitespace on each individual string before I add it to the arrayList, but the output still has the spaces.
Scanner input = new Scanner(System.in);
ArrayList<String> userWords = new ArrayList<String>();
ArrayList<String> SplituserWords = new ArrayList<String>();
System.out.println("Please enter your phrase: ");
userWords.add(input.nextLine());
for (int index = 0; index < userWords.size(); index++) {
String[] split = userWords.get(index).split("\\s+");
for (String word : split) {
word.replaceAll("\\s+","");
SplituserWords.add(word);
}
System.out.println(SplituserWords);
I suggest just taking advantage of the built-in Arrays#toString() method here:
String words = input.nextLine();
String output = Arrays.toString(words.split(" ")).replace(" ", "");
System.out.println(output); // [I,walked,my,dog]
When you are writing System.out.println(SplituserWords);, you are implicitly calling ArrayList#toString() which generates the list's string and that includes spaces after commas.
You can instead generates your own string output, for example with:
System.out.println("[" + String.join(",", SplituserWords) + "]");
If you insist on using List, it will do it for you.
String input = "I walked my dog";
List<String> SplitUserWords = Arrays.asList(input.split(" "));
String output = SplitUserWords.toString().replace(" ", "");
System.out.println(output); //[I,walked,my,dog]
I tried to remove whitespace on each individual string before I add it to the arrayList, but the output still has the spaces.
That won't work because that isn't the problem. The issue is that it is the list implementation that formats the output for you inserts a space after each comma. It does this in the toString() method. To avoid having to explicitly call replace each time you can also do it like this by overidding toString() when you create your List.
List<String> myList = new ArrayList<>(List.of("I","walked","my", "dog")) {
#Override
public String toString() {
// use super to call the overidden method to format the string
// then remove the spaces and return the new String
return super.toString().replace(" ", "");
}
};
System.out.println(myList);
myList.addAll(List.of("and", "then","fed", "my", "cat"));
System.out.println(myList);
prints
[I,walked,my,dog]
[I,walked,my,dog,and,then,fed,my,cat]
You can also subclass ArrayList as follows. Here I have added the three constructors that ArrayList implements. Note that is is a somewhat extreme solution and may not be worth it for occasionally reformatting of the output. I included it for your consideration.
class MyArrayList<E> extends ArrayList<E> {
public MyArrayList() {
super();
}
public MyArrayList(int capacity) {
super(capacity);
}
public MyArrayList(Collection<? extends E> c) {
super(c);
}
#Override
public String toString() {
return super.toString().replace(" ", "");
}
}
And it would work like so.
MyArrayList<String> myList = new MyArrayList<>(List.of("This", "is", "a","test."));
System.out.println(myList);
prints
[This,is,a,test.]
I am trying to understand how .previous() method actually works.
In this line:
System.out.printf("%s ", a.previous());
It first prints the actual a item in line, then goes to the previous or it just gets the previous value?
Because l1.size() is 5, then the loop condition checks if the 5th position has a previous value?
Basically I just need to know how this works in order. Thank you in advance.
public static void main(String[] args) {
String[] a = {"apple", "bee", "orange", "noob", "win"};
List<String> list1 = new LinkedList<String>();
for (String s : a) {
list1.add(s);
}
System.out.println("List1 Size: " + list1.size());
reverse(list1);
}
//reverse method
public static void reverse(List<String> l1) {
ListIterator<String> a = l1.listIterator(l1.size());
while (a.hasPrevious()) {
System.out.printf("%s ", a.previous());
}
}
a.previous gets the value that comes directly before the current value. It does this by first checking if the current a has a value that comes directly before it (i.e. a node that points at the value a). If it does, it then returns the value. Which then in turn is printed by your System.out.println
I have a Java program that ask for five string inputs from the user. My aim is to search for a particular element in the list containing 'a'. On running the code it can be seen that, it only returns the first occurrence of the String that has the element 'a'. list Eg: (aleah, alex, arthur, john, eerie).
Obtained Output:aleah.
Expected Output:It should have returned aleah, alex and arthur.
I have pasted my code below kindly have a look at it.
public ArrayList<String> searchName(String sn){
// String sn is the the search for character value (e.g 'a' or 'aa')
ArrayList<String> searches = new ArrayList<>();
for(String n : names){
// names list is declared in the other method and handles all the name values
// loop through the list. Am i using the right loop?
if(n.contains(sn)){
// if a specific index in the list contains the sn
searches.add(n);
// stored in in the new list searches
displaySearches(searches);
// called displaySearches and passed the arralist searches.
}
else
System.out.println("No results for " + sn);
break;
}
return searches;
}
public void displaySearches(ArrayList<String> searches){
for(String s: searches){
System.out.println(s);
// populates all the search results from the list.
}
}
The problem lies here:
else
System.out.println("No results for " + sn);
break;
Setting a break statement means that it'll break the full loop, not checking any further items - and it always does this after the first string from the array, because you haven't put any brackets for your else.
Removing the break; should fix your issue.
Your else statement is creating the problem here. Just remove it or place it outside the loop.
You can do something like this.
public ArrayList<String> searchName(String sn){
ArrayList<String> searches = new ArrayList<>();
//1. First add all the matches to the `searches` List.
for(String n : names){
if(n.contains(sn)){
searches.add(n);
}
}
//2. Now if the `searches` list is NOT empty, it means that
// there were some matches, then display those matches
if(!searches.isEmpty()) {
displaySearches(searches);
} else {
//3. Otherwise print that there wasn't any match.
System.out.println("No results for " + sn);
}
return searches;
}
public void displaySearches(ArrayList<String> searches){
for(String s: searches){
System.out.println(s);
}
}
İf you want to find all strings containing 'A's, then, else part should be deleted. Since you don't use parenthesis after else , second n value is not checked because of break statement.
I recommend you to remove else part of your code and check again. Moreover, display function can be called after loop is completed.
Because your breaking the loop after the else condition
public ArrayList<String> searchName(String sn){
// String sn is the the search for character value (e.g 'a' or 'aa')
ArrayList<String> searches = new ArrayList<>();
for(String n : names){
// names list is declared in the other method and handles all the name values
// loop through the list. Am i using the right loop?
if(n.contains(sn)){
// if a specific index in the list contains the sn
searches.add(n);
// stored in in the new list searches
displaySearches(searches);
// called displaySearches and passed the arralist searches.
}
}
if(searches.isEmpty()){
System.out.println("No results for " + sn);
}else{
displaySearches(searches);
}
return searches;
}
public void displaySearches(ArrayList<String> searches){
for(String s: searches){
System.out.println(s);
// populates all the search results from the list.
}
}
I have to check whether an arraylist contains any of the value passed through an object.
Consider an arraylist with values "abc", "jkl","def", "ghi".
And String check="abc,ghi"
We have to check whether any of the value in string (abc or ghi) is present in the arraylist and we can stop checking when a match is found.
Traditionally, we can split the String check with comma and use arraylist.contains() in iteration for each comma separated values.
But this is time consuming. Is there any better way to do this check.
One way would be to use the retainAll method and Sets.
Example
// note an additional "ghi" here
List<String> original = new ArrayList<String>(Arrays.asList(new String[]{"abc", "jkl","def", "ghi", "ghi"}));
Set<String> clone = new HashSet<String>(original);
Set<String> control = new HashSet<String>(Arrays.asList(new String[]{"abc","ghi"}));
clone.retainAll(control);
System.out.println(clone.equals(control));
Output
true
This is still O(n), but you could build a set from the search strings and just iterate over the list once:
HashSet<String> checks = new HashSet<String>();
checks.addAll(Arrays.asList(check.split(",")));
for (String item : arraylist) {
if (checks.contains(item)) {
// Found one
}
}
You could transform check into a regexp and loop only once through the ArrayList.
String check = "abc,ghi";
Pattern p = Pattern.compile("(" + check.replace(',', '|') + ")");
List<String> list = Arrays.asList(new String[] { "abc", "jkl", "def", "ghi" });
for (String element : list) {
if (p.matcher(element).matches()) {
System.out.println("match: " + element);
}
}
So I have a problem that takes the names of people from a user and stores them in an ArrayList(personalNames). After that I need to take that list and remove any name that has anything besides letters a-z (anything with numbers or symbols) in it and put them into a separate ArrayList(errorProneNames) that holds the errors. Could someone help me with the removal part?
public class NameList {
public static void main(String[] args) {
ArrayList<String> personalNames = new ArrayList<String>();
Scanner input = new Scanner(System.in);
String answer;
do{
System.out.println("Enter the personal Names: ");
String names = input.next();
personalNames.add(names);
System.out.println("would you like to enter another name (yes/no)?");
answer = input.next();
} while (answer.equalsIgnoreCase("yes"));
ArrayList<String> errorProneNames = new ArrayList<String>();
}
}
If it's the "how do I remove an element from an ArrayList<>" part which is causing problems, and you want to check all the values, you probably want to use an Iterator and call remove on that:
for (Iterator<String> iterator = personalNames.iterator(); iterator.hasNext(); ) {
String name = iterator.next();
if (isErrorProne(name)) {
iterator.remove();
}
}
Note that you mustn't remove an element from a collection while you're iterating over it in an enhanced-for loop except with the iterator. So this would be wrong:
// BAD CODE: DO NOT USE
for (String name : personalNames) {
if (isErrorProne(name)) {
personalNames.remove(name);
}
}
That will throw a ConcurrentModificationException.
Another option would be to create a new list of good names:
List<String> goodNames = new ArrayList<>();
for (String name : personalNames) {
if (!isErrorProne(name)) {
goodNames.add(name);
}
}
Now, if your real problem is that you don't know how to write the isErrorProne method, that's a different matter. I suspect that you want to use a regular expression to check that the name only contains letters, spaces, hyphens, and perhaps apostrophes - but you should think carefully about exactly what you want here. So you might want:
private static boolean isErrorProne(String name) {
return !name.matches("^[a-zA-Z \\-']+$");
}
Note that that won't cope with accented characters, for example. Maybe that's okay for your situation - maybe it's not. You need to consider exactly what you want to allow, and adjust the regular expression accordingly.
You may also want to consider expressing it in terms of whether something is a good name rather than whether it's a bad name - particularly if you use the last approach of building up a new list of good names.
Here is your solution :
String regex = "[a-zA-Z]*";
for (String temp : personalNames ) {
if (!temp.matches(regex)){
errorProneNames.add(temp);
personalNames.remove(temp);
}
}
You can use the remove() method of ArrayList
personalNames.remove("stringToBeRemoved");
Lot of overloaded methods are available. You can delete with index, Object(String itself) etc. You can see Javadocs for more info.
Also to remove all String having anything but a-z letters you can use regex. Logic is as follows
String regex = "[a-zA-Z]*";
String testString = "abc1";
if(!testString.matches(regex)){
System.out.println("Remove this");
}
As Jon pointed out while iterating over the List do not use the Lists's remove() method but the iterators remove() method.
There are two ways you can do this:
The first is to iterate backwards through the list, remove them, then add them into the second list. I say to do it backwards, because it will change the index.
for (int i = personalNames.size()-1; i >=0; i++) {
if (isBadName(personalNames.get(i)]){
errorProneNames.add(personalNames.get(i));
personalNames.remove(i);
}
}
The second way is to use the Iterator provided by ArrayList (personalNames.iterator()). This will allow you to go forward.
I would probably do this
// Check that the string contains only letters.
private static boolean onlyLetters(String in) {
if (in == null) {
return false;
}
for (char c : in.toCharArray()) {
if (!Character.isLetter(c)) {
return false;
}
}
return true;
}
public static void main(String[] args) {
ArrayList<String> personalNames = new ArrayList<String>();
ArrayList<String> errorProneNames = new ArrayList<String>(); // keep this list here.
Scanner input = new Scanner(System.in);
String answer;
do {
System.out.println("Enter the personal Names: ");
String names = input.next();
if (onlyLetters(names)) { // test on input.
personalNames.add(names); // good.
} else {
errorProneNames.add(names); // bad.
}
System.out
.println("would you like to enter another name (yes/no)?");
answer = input.next();
} while (answer.equalsIgnoreCase("yes"));
}
get an iterator from list, while itr has next element give it to a method for example isNotProneName which takes a String and returns true or false, if the given String matches not your needs. if false returned remove string from itr and add it to the other list
Use regex [a-zA-Z ]+ with String.matches to test error-prone name and Iterator to remove.
Iterator<String> it=personalNames.iterator();
while(it.hasNext()){
String name=it.next();
if(name.matches("[a-zA-Z ]+")){
it.remove();
}
}