# Sorting ArrayList

Create several classes of flowers that extend abstract flower. all fields -- random.

1. make a bunch of 20 different flowers
2. calculate the price of the bunch
3. sort bunch by freshness of flowers
4. find flowers with stalks in a certain range
5. find average level of freshness of the bunch

Solution:

public abstract class Flower implements Comparable<Flower> {

public String name;
public double freshness;
public double stalk;
public double price;

public Flower(String name) {
super();
Random rand = new Random();
this.name = name;
this.freshness = rand.nextDouble() * 100;
this.stalk = rand.nextDouble() * 150 + 30;
this.price = rand.nextDouble() * 1000 + 1;
}

// getters and setters

@Override
public int compareTo(Flower that) {
return (int) (that.getFreshness() - this.getFreshness());
}

@Override
public String toString() {
return this.name + " " + this.freshness + "\n";
}


Every class of a particular flower looks like this:

public class Rose extends Flower {

public Rose() {
super("rose");
}

}


Main method:

public class Main {

public static List<Flower> flowers = new ArrayList<Flower>();
public static List<Flower> bunch = new ArrayList<Flower>();
public static Random random = new Random();
public static double bunchPrice;
public static double stalkMin = 30;
public static double stalkMax = 100;

public static void main(String[] args) {

for (int i = 0; i < 20; i++) {
bunchPrice = bunchPrice + bunch.get(i).getPrice();

}
System.out.println("the bunch ====================");
System.out.println(bunch);

System.out.println("\nprice of the bunch ====================");
System.out.println(bunchPrice);

System.out.println("\nflowers sorted by price ====================");

Collections.sort(bunch);
System.out.println(bunch);

System.out.println("\nflowers with stalks in range from " + stalkMin + " to " + stalkMax + "====================");
for(Flower f: bunch) {
if(f.getStalk() > stalkMin && f.getStalk() < stalkMax){
System.out.println(f.getName() + " " + f.getStalk());
}
}

System.out.println("\naverage level of freshness in the bunch ====================");
double sumFreshness = 0;
for(Flower f: bunch) {
sumFreshness = sumFreshness + f.getFreshness();
}
System.out.println(sumFreshness/ bunch.size());
}

}

• Please take more care of code-formatting. – Caridorc Jul 22 '15 at 14:08
• You may select your code and press Control-K for faster indenting. – Caridorc Jul 22 '15 at 14:08
• Welcome to CR! Are you on Java 8? – h.j.k. Jul 22 '15 at 15:56

@Override
public int compareTo(Flower that) {
return (int) (that.getFreshness() - this.getFreshness());
}


This may not work as what you expect if you are comparing two freshness ratings that are less than 1... Consider:

• Flower A: 1.1
• Flower B: 1.0

When you subtract B's freshess from A's, you get 1.1 - 1.0 = 0.1. Now cast that to an int and you get... 0. What you are looking for here is probably Double.compare(double, double).

Now, if you happen to be on Java 8, you can make use of Streams to make your code simpler... As a guide, I'll illustrate how points (2) and (3) can be achieved (assuming your bunch is created as a List).

• Calculate price of bunch

Assuming you have a getter method on your Flower, e.g. getPrice():

return bunch.stream().mapToDouble(Flower::getPrice).sum();


This firstly converts our Stream<Flower> into a DoubleStream via mapToDouble(), before calling the sum() to get our answer. No explict looping, you simply perform the required series of operations on the Stream.

• Sort bunch by freshness of flowers

Originally, I thought the SortedSet approach suggested by @Nicolas Gallegos is pretty OK, but then realized it being a Set will not allow duplicate objects. No worries using the Stream approach still though, as you can easily sort it first. Assuming you have a getter method on your Flower, e.g. getFreshness():

return bunch.stream().sorted(Comparator.comparing(Flower::getFreshness))
.collect(Collectors.toList());


We construct a Comparator via comparing(), which is used in the sorted() method. Having sorted the Stream, we then collect the elements into a resulting List using Collectors.toList().

I hope the two examples have given you a good enough sneak peek at the features of Java 8 Streams. :)

    public static List<Flower> flowers = new ArrayList<Flower>();
public static List<Flower> bunch = new ArrayList<Flower>();
public static Random random = new Random();
public static double bunchPrice;
public static double stalkMin = 30;
public static double stalkMax = 100;


Class fields are meant to hold data about the instances of the class that cross past any particular instance. They allow you to store and use data across multiple method calls. Here, you are using these variables entirely in a single method. They should be local variables defined in the method.

It's also worth noting that everything but bunchPrice could be final.

        for (int i = 0; i < 20; i++) {
bunchPrice = bunchPrice + bunch.get(i).getPrice();

}


Since you use it again immediately, you may want to consider defining a variable for the flower that you create.

        for (int i = 0; i < 20; i++) {
Flower flower = flowers.get(random.nextInt(flowers.size()));
bunchPrice += flower.getPrice();
}


It also makes it easier to follow what you are doing.

You can save some typing by using the += operator.

If you want to have your flowers sorted, you should use SortedSet class, and define the Comparator by the field you want so sort. This way you'll only have to add the flower, and automatically will be sorted :).

• but the set can only contain unique values whereas the bunch can have several flowers of the same type – rigby Jul 23 '15 at 12:27

I'd use:

return String.format("%s %f", this.name, this.freshness);


return this.name + " " + this.freshness + "\n";


for clearness: It shows the structure of the resulting string and the types of the parameters at first glance.

I'd also omit "\n" since it's up to the caller whether he or she wants a line break. If he or she does not want one they are fighting a losing battle with your implementation imposing one.

I feel like you could reduce the number of for loops in main. Right after creating a flower why not add to the sum of freshness and find flowers in the range of thickness (still need a loop later for this, but it could be shorter as not all flowers are necessarily in the range).

public class Main {

public static List<Flower> flowers = new ArrayList<Flower>();
public static List<Flower> bunch = new ArrayList<Flower>();
public static Random random = new Random();
public static double bunchPrice;
public static double stalkMin = 30;
public static double stalkMax = 100;

public static void main(String[] args) {

double sumFreshness = 0;
List<Flower> inRange=new ArrayList<Flower>();

for (int i = 0; i < 20; i++) {
bunchPrice = bunchPrice + bunch.get(i).getPrice();
sumFreshness += bunch.get(i).getFreshness();
if(bunch.get(i).getStalk() > stalkMin && bunch.get(i).getStalk() < stalkMax){
}
}
System.out.println("the bunch ====================");
System.out.println(bunch);

System.out.println("\nprice of the bunch ====================");
System.out.println(bunchPrice);

System.out.println("\nflowers sorted by price ====================");

Collections.sort(bunch);
System.out.println(bunch);

System.out.println("\nflowers with stalks in range from " + stalkMin + " to " + stalkMax + "====================");
for(Flower f: inRange) {
System.out.println(f.getName() + " " + f.getStalk());
}

System.out.println("\naverage level of freshness in the bunch ====================");
System.out.println(sumFreshness/ bunch.size());
}

}