0

I didn't think I would have as much trouble since I've done this with a brute force method with regular arrays. I'm trying to use Collections.frequency to group together repeated entries from a user and display the number of times each entry occurs (if more than once); however, the output just prints as they are entered. I have two classes, which I will show below:

    public class Flower {

private String name;
private String color;
private String smell;
private String hasThorns;

public Flower(String name, String color, String smell, String hasThorns) {
    this.name = name;
    this.color = color;
    this.smell = smell;
    this.hasThorns = hasThorns;
}
public void setName(String name) {
    this.name = name;
}
public void setColor(String color) {
    this.color = color;
}
public void setSmell(String smell) {
    this.smell = smell;
}
public void setThorns(String hasThorns) {
    this.hasThorns = hasThorns;
}
public String getName() {
    return name;
}
public String getColor() {
    return color;
}
public String getSmell() {
    return smell;
}
public String getThorns() {
    return hasThorns;
}
public String toString() {
    return "Name: " + this.name + ", Color: " + this.color + ", Scent? " + this.smell + ", Thorns? " + this.hasThorns;
}
}//end Flower class



    import java.util.*;

public class Assignment3 {
String name = new String();
String color = new String();
String smell = new String();
String hasThorns = new String();

//ArrayList<Flower> flowerPack = new ArrayList<Flower>();
boolean found = false;
public static void main(String[] args) {
    new Assignment3();
}

// This will act as our program switchboard
public Assignment3() {
    Scanner input = new Scanner(System.in);
    ArrayList<Flower> flowerPack = new ArrayList<Flower>();

    System.out.println("Welcome to my flower pack interface.");
    System.out.println("Please select a number from the options below");
    System.out.println("");

    while (true) {
        // Give the user a list of their options
        System.out.println("1: Add an item to the pack.");
        System.out.println("2: Remove an item from the pack.");
        System.out.println("3: Search for a flower.");
        System.out.println("4: Display the flowers in the pack.");
        System.out.println("5: Filter flower pack by incomplete name");
        System.out.println("0: Exit the flower pack interface.");

        // Get the user input
        int userChoice = input.nextInt();

        switch (userChoice) {
            case 1:
                addFlower(flowerPack);
                break;
            case 2:
                removeFlower(flowerPack);
                break;
            case 3:
                searchFlowers(flowerPack);
                break;
            case 4:
                displayFlowers(flowerPack);
                break;
            case 5:
                filterFlowers(flowerPack);
                break;
            case 0:
                exitInterface();
                break;
            default:
                System.out.println("Invalid entry. \nPlease choose between 1-5, or 0: ");
                break;
        }
    }
}
private void addFlower(ArrayList<Flower> flowerPack) {
    // TODO: Add a flower that is specified by the user
    Flower newFlower = new Flower(name, color, smell, hasThorns);

    Scanner input = new Scanner(System.in);

    if(flowerPack.size() < 25)
    {
        System.out.println("Enter the name of the flower you wish to add: ");
        newFlower.setName(input.nextLine());
        System.out.println("Enter the color of the flower: ");
        newFlower.setColor(input.nextLine());
        System.out.println("Does the flower have a scent? Yes or No: ");
        newFlower.setSmell(input.nextLine());
        System.out.println("Does the flower have thorns? Yes or No: ");
        newFlower.setThorns(input.nextLine());

        flowerPack.add(newFlower);
    }
    else
    {
        System.out.println("You may only hold 25 flowers in your flower pack. Please remove at least one before adding another.");
    }
}
private void removeFlower(ArrayList<Flower> flowerPack) {
    // TODO: Remove a flower that is specified by the user
    Scanner input = new Scanner(System.in);

    System.out.println("Enter the name of the flower you want to remove: ");
    String deleteName = input.nextLine();
    System.out.println("Enter the color of the flower you want to remove: ");
    String deleteColor = input.nextLine();
    System.out.println("Is this a flower with a scent? Yes or No: ");
    String deleteSmell = input.nextLine();
    System.out.println("Is this a flower with thorns? Yes or No: ");
    String deleteThorns = input.nextLine();

    for(int i = 0; i < flowerPack.size(); i++) {
        if(flowerPack.get(i).getName().equals(deleteName) && flowerPack.get(i).getColor().equals(deleteColor) && flowerPack.get(i).getSmell().equals(deleteSmell) && flowerPack.get(i).getThorns().equals(deleteThorns))
        {
            flowerPack.remove(i);
            found = true;
            break;
        }
        if(found)
        {
            System.out.println("That flower was successfully removed from your inventory.");
        }
        else
        {
            System.out.println("That flower was not found in your inventory.");
        }
    }
}
private void searchFlowers(ArrayList<Flower> flowerPack) {
    // TODO: Search for a user specified flower

}

This is where I am having the problem. I haven't started the other methods (search, filter) since I want it to display correctly before moving on.

private void displayFlowers(ArrayList<Flower> flowerPack) {
    // TODO: Display flowers using any technique you like

    for(Flower flower : flowerPack) {
        int duplicates = Collections.frequency(flowerPack, flower);
        System.out.println(flower + " - " + duplicates);
    }
}

private void filterFlowers (ArrayList<Flower> flowerPack) {
    // TODO Filter flower results

}
private void exitInterface() {
    Scanner input = new Scanner(System.in);
    System.out.println("Are you sure you want to exit the flower pack interface? Y or N: ");
    while(true) {
        String answer = input.next();
        if(!"Y".equalsIgnoreCase(answer) && !"N".equalsIgnoreCase(answer))
        {
            System.out.println("Please enter Y or N (not case-sensitive): ");
        }
        if("Y".equalsIgnoreCase(answer))
        {
            System.out.println("Thank you for using the flower pack interface. See ya later!");
            System.exit(0);
        }
        if("N".equalsIgnoreCase(answer))
        {
            break;
        }
    }
}
}

I've seen examples with Maps/HashSets, but I'm too unfamiliar with those concepts to utilize them at this point.

This is the output, which is incorrect. Could someone give me a hint as to where I went wrong?

    Name: rose, Color: red, Scent? yes, Thorns? yes - 1
    Name: rose, Color: red, Scent? yes, Thorns? yes - 1
    Name: rose, Color: pink, Scent? yes, Thorns? no - 1
    Name: daffodil, Color: yellow, Scent? yes, Thorns? no - 1

As you can see, the first two entries should read as one, but with -2:

Like:

    Name: rose, Color: red, Scent? yes, Thorns? yes - 2
DevOpsSauce
  • 1,319
  • 1
  • 20
  • 52
  • Please read [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – Andreas Oct 03 '15 at 19:10
  • I didn't know what was needed in case someone wanted to run it and see the results themselves. I've seen complaints where someone included just a little snippet of code and the comments were along the lines of "Where is your other code? I can't work with this, etc etc." @Andreas – DevOpsSauce Oct 03 '15 at 22:21
  • 1
    Yeah, that's the implicit conflict between "minimal" and "complete". The trick is to showcase the issue with the least amount of code, and sometimes you actually end up finding the error yourself when doing that. Just remember that you only post the question once, but it's read many times by lots of people, so any reduction/simplification helps everybody. Also, improving the indentation of the code helps people read it. – Andreas Oct 04 '15 at 02:56

2 Answers2

1

Your flower Class needs a equals and hashcode Method, otherwise java cant tell if two flower objects are the same.

hinneLinks
  • 3,673
  • 26
  • 40
0

Collections.frequency uses Flower.equals to decide if two flowers are the same or not. Since you haven't overridden the default implementation of equals, all instances of Flower appear to be unique.

You can use your IDE to generate an equals (and hashCode) implementation that should work well, and then the frequency count will become correct, as logically equal flowers will be detected as such.

For example, as generated by IntelliJ, add this in Flower:

@Override
public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }

    Flower flower = (Flower) o;

    if (color != null ? !color.equals(flower.color) : flower.color != null) {
        return false;
    }
    if (hasThorns != null ? !hasThorns.equals(flower.hasThorns) : flower.hasThorns != null) {
        return false;
    }
    if (name != null ? !name.equals(flower.name) : flower.name != null) {
        return false;
    }
    if (smell != null ? !smell.equals(flower.smell) : flower.smell != null) {
        return false;
    }

    return true;
}

@Override
public int hashCode() {
    int result = name != null ? name.hashCode() : 0;
    result = 31 * result + (color != null ? color.hashCode() : 0);
    result = 31 * result + (smell != null ? smell.hashCode() : 0);
    result = 31 * result + (hasThorns != null ? hasThorns.hashCode() : 0);
    return result;
}
janos
  • 120,954
  • 29
  • 226
  • 236
  • I found that by clicking "Code" in my IntelliJ taskbar and clicking Override Methods. Though I don't know anything about this, I can look more into it. This seems far beyond what we've learned so far. I wish we were taught "what if" situations. We were given the option to display the arraylist however we wanted, and I wanted to use the same output as I did with regular arrays. – DevOpsSauce Oct 03 '15 at 19:09
  • Hey, what is the "result = 31" and the "?" in the hashCode() method? – DevOpsSauce Oct 03 '15 at 19:10
  • See this post: http://stackoverflow.com/a/27609/641955 (and the documentation about equals and hashCode) – janos Oct 03 '15 at 19:12
  • I started trying to delve into the Override methods, but it's far beyond what I'm doing in class. I need to work around that using different techniques. Sorry. I don't even have to display it that way (counting dupes), but I want to learn. – DevOpsSauce Oct 03 '15 at 21:02
  • You can copy-paste the methods from my post, and it should just work. You don't really need to go deep here, the post I linked sums it up well. – janos Oct 03 '15 at 21:06
  • I just need to fix my loop structure, since it does tell me how many duplicates, but it prints those duplicates however many times they occur. Will continue to work on that. – DevOpsSauce Oct 03 '15 at 21:48
  • To print the duplicates only once, here's a quick fix for your loop: `for (Flower flower : new HashMap<>(flowerPack)) { ... }` – janos Oct 03 '15 at 22:21
  • I appreciate the code snippet of the Override methods, as well as the tip on creating duplicates only once; however, I decided to just keep it simple since I wasn't actually required to print dupes. Thank you for introducing me to those methods, but I will feel extremely guilty if I actually use them since I didn't actually learn anything from them. Get what I mean? @janos – DevOpsSauce Oct 03 '15 at 22:25
  • If you want to use `Collections.frequency`, then the only way is to implement `equals` and `hashCode` as I explained. Or you can write your own algorithm instead of using `Collections.frequency`. It's up to you. – janos Oct 09 '15 at 13:49