American Idiot
American Idiot

Reputation: 35

How to remove a range of string objects from an arraylist based on first initials inputted by the user?

So I have a project where I need to create an arraylist of all fifty states. Then I must allow the user to enter two different letters of the alphabet. Then I have to remove all of the states beginning with those letters and all states in between. E.g. if someone entered "D-I", all states with that begin with D-I should be removed.

I've come up with this program so far, however when I run it, not only does it remove all of the states within the range of letters I input, but it also removes all of the states before the first letter. E.g. if I type in "D-I", all of the states that begin with A-I will be removed when it should be all states beginning with D-I.

Can someone help me out with this?

import java.util.ArrayList;
import java.util.Scanner;

public class States {
    public static void main(String[] args) {
        String removeStates;
        String firstInitial;
        String secondInitial;
        String stateInitial;
        int first = 0;
        int last = 0;
        
        Scanner input = new Scanner(System.in);
        ArrayList<String> states = new ArrayList<>();
        
        states.add("Alabama");
        states.add("Alaska");
        states.add("Arizona");
        states.add("Arkansas");
        states.add("California");
        states.add("Colorado");
        states.add("Connecticut");
        states.add("Delaware");
        states.add("District of Columbia");
        states.add("Florida");
        states.add("Georgia");
        states.add("Hawaii");
        states.add("Idaho");
        states.add("Illinois");
        states.add("Indiana");
        states.add("Iowa");
        states.add("Kansas");
        states.add("Kentucky");
        states.add("Louisiana");
        states.add("Maine");
        states.add("Maryland");
        states.add("Massachusetts");
        states.add("Michigan");
        states.add("Minnesota");
        states.add("Mississippi");
        states.add("Missouri");
        states.add("Montana");
        states.add("Nebraska");
        states.add("Nevada");
        states.add("New Hampshire");
        states.add("New Jersey");
        states.add("New Mexico");
        states.add("New York");
        states.add("North Carolina");
        states.add("North Dakota");
        states.add("Ohio");
        states.add("Oklahoma");
        states.add("Oregon");
        states.add("Pennsylvania");
        states.add("Rhode Island");
        states.add("South Carolina");
        states.add("South Dakota");
        states.add("Tennessee");
        states.add("Texas");
        states.add("Utah");
        states.add("Vermont");
        states.add("Virginia");
        states.add("Washington");
        states.add("West Virginia");
        states.add("Wisconsin");
        states.add("Wyoming");
        
        System.out.println(states.toString());
        
        System.out.print("Enter the range of the states you would like to remove based on the first initials (e.g. A-D [not case sensitive]): ");
        
        removeStates = input.nextLine();
        
        firstInitial = removeStates.substring(0, 1);
        
        secondInitial = removeStates.substring(2);
        
        for (int i = 0; i < states.size(); i++) {
            stateInitial = states.get(i).substring(0, 1);
            
            if (stateInitial.equalsIgnoreCase(firstInitial) || stateInitial.equalsIgnoreCase(secondInitial)) {
            
                for (int j = i+1; j>0; j--){
                    states.remove(i);
                    i--;
                }
            }
        }
        System.out.println(states.toString());

    }
}

Here's what my output looks like right now. The bottom/third line is where the issue is. As you can see, when I entered "G-K" (this isn't case sensitive by the way), it removed all of the states beginning with A-K instead of those beginning with G-K

[Alabama, Alaska, Arizona, Arkansas, California, Colorado, Connecticut, Delaware, District of Columbia, Florida, Georgia, Hawaii, Idaho, Illinois, Indiana, Iowa, Kansas, Kentucky, Louisiana, Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana, Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina, North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia, Wisconsin, Wyoming]
Enter the range of the states you would like to remove based on the first initials (e.g. A-D [not case sensitive]): g-k
[Louisiana, Maine, Maryland, Massachusetts, Michigan, Minnesota, Mississippi, Missouri, Montana, Nebraska, Nevada, New Hampshire, New Jersey, New Mexico, New York, North Carolina, North Dakota, Ohio, Oklahoma, Oregon, Pennsylvania, Rhode Island, South Carolina, South Dakota, Tennessee, Texas, Utah, Vermont, Virginia, Washington, West Virginia, Wisconsin, Wyoming]

Upvotes: 1

Views: 58

Answers (4)

Christoph Bimminger
Christoph Bimminger

Reputation: 1018

Instead of the loops, you could simply use the facts, that

  • a List is sorted
  • the comparator of a string compares lexicographically, so the order is A, Aa, Aaa, Aab, Abb, Baa,...
  • the List interface implements a "removeIf" method which allows you to test a string against a rule which you implement

So, instead of your for-loops, you could simply code:

    firstInitial = removeStates.substring(0, 1);

    secondInitial = removeStates.substring(2);

    states.removeIf(new Predicate<String>() {

        @Override
        public boolean test(String t) {
            boolean isBeforeFirstInitial = (firstInitial.compareTo(t) >=0);
            boolean isAfterLastInitial = (secondInitial.compareTo(t) <=0);
            boolean startsWithLastInitial = t.startsWith(secondInitial);

            return !(isBeforeFirstInitial||isAfterLastInitial)||startsWithLastInitial;
        }
    });

don't forget to convert the initials to uppercases (your text states that the input is NOT case sensitive)

Upvotes: 1

Kartik
Kartik

Reputation: 7917

This can be done in a single statement using removeIf():

states.removeIf(s -> s.charAt(0) >= 'D' && s.charAt(0) <= 'I');

You can replace 'D' with removeStates.charAt(0) and 'I' with removeStates.charAt(2).

Upvotes: 2

Malcolm Crum
Malcolm Crum

Reputation: 4879

Here is an alternate method to remove the unwanted states, using streams:

char firstInitial = removeStates.charAt(0);
char secondInitial = removeStates.charAt(2);

Collection<String> statesToRemove = states.stream()
       .filter(state -> state.charAt(0) >= firstInitial)
       .filter(state -> state.charAt(0) <= secondInitial)
       .collect(Collectors.toList());

states.removeAll(statesToRemove);

You could also just adjust the filter to filter just the remaining states to make it simpler still.

Upvotes: 1

Java Coder
Java Coder

Reputation: 33

Not trying to sound mean here, but it did, what you wrote:

for (int j = i+1; j>0; j--){
                states.remove(i);
                i--;
            }

Let's say you had the first letter be a 'C', the first index you're outer loop would enter into the inner loop would be i == 4 (California). You then call the inner loop with a starting value for j = i+1 = 5, and gradually move down the array indices. So you remove 5 (which is one to high btw.), then 4, then 3, then 2 and so on. So once you found the first one, you remove all the entries leading up to it.

Upvotes: 0

Related Questions