badatprog
badatprog

Reputation: 19

How do i write this methods with streams and lambdas?

We started with streams and lambdas today in programming class and i have to do an exercise.

The first task was to write a method that calculates the average of even numbers in a list. I have written this code but obviously i did not make use of streams.

public static double average(List<Integer> list) {

    double sum = 0;
    int i = 0;
    for (Integer integer : list) {
        if (integer % 2 == 0) {
            i++;
            sum += integer;
        }
    }
    return (sum / i);
}

EDIT Solution:

int sum = list.stream().filter(integer -> integer % 2 == 0).mapToInt(Integer::intValue).sum();
long count = list.stream().filter(integer -> integer % 2 == 0).count();

The second task was to write a method that selects all strings that start with "a" (case insensitive) or have 3 characters and change it to upper case. My code:

public static List<String> upperCase(List<String> list) {

    for(int i = 0; i < list.size(); i++){
        if(list.get(i).length() == 3 || Character.toString(list.get(i).charAt(0)).equalsIgnoreCase("a")){
            list.set(i, list.get(i).toUpperCase());
        }
    }
    return list;
}

EDIT: Solution:

public static List<String> upperCase(List<String> list) {


    List<String> newListOfStrings = list.stream().map(string -> string.length() == 3 ||
            Character.toString(string.charAt(0)).equalsIgnoreCase("a") ? string.toUpperCase() : string).collect(Collectors.toList());
    return newListOfStrings;

The last task was to return the list but add "g" to even numbers and "u" to odd numbers. My code:

public static String getString(List<Integer> list){
    String s = "";
    for(Integer integer : list){
        if(integer % 2 == 0){
            s += integer.toString() + "g,";}
        else {
            s += integer.toString()+ "u,";
        }

    }
    return s.substring(0, s.length()-1);
}

EDIT: Solution:

public static String getString (List < Integer > list) {

    String result = list.stream()
            .map(integer -> integer % 2 == 0 ?
                    String.format("%d%s", integer, "g") : String.format("%d%s", integer, "u"))
            .collect(Collectors.joining(","));
    return result;

I would really appreciate if someone could tell me how the first task would look like with streams. I will try the two others on my own.

Kind regards

Upvotes: 0

Views: 80

Answers (1)

Nikolas
Nikolas

Reputation: 44496

The first task was to write a method that calculates the average of even numbers in a list.

The point is to change the boxed Stream<Integer to IntStream which provides method for aggregating operation such as sum, average, min, max etc.

double average = list.stream().mapToInt(i -> i).average().getAsDouble;

Remember, the NoSuchElementException might be thrown if no average is present in OptionalDouble.

The second task was to write a method that selects all strings that start with "a" (case insensitive) or have 3 characters and change it to upper case.

You forEach method at the end of the stream is a terminal operation that requires a Consumer, which consumes the method. Although you call toUpperCase, it doesn't change the original collection and the result is thrown (unless you print it out).

You wan to perform the mapping of the qualified strings using method map. As long as you want only to modify these values and keep the remaining at the same time, you cannot use filter as long as it can modify the number of items streamed. Do this:

List<String> newListOfStrings = listOfStrings.stream()
    .map(string -> string.length() == 3 || string.startsWith("a") ? 
                   string.toUpperCase() : string)
    .collect(Collectors.toList());

Notice I have used startsWith method that is easier to use. Your usage of charAt is not incorrect, though.

The last task was to return the list but add "g" to even numbers and "u" to odd numbers.

Not the best, but fairly acceptable solution is again using mapping method map and finally Collectors.joining(",") that joins the items to a string with a delimiter. Therefore you don't need to bother with , characters.

String result = list.stream()
    .map(integer -> integer % 2 == 0 ? integer + "g" : integer + "u")
    .collect(Collectors.joining(","));

// I find String.format better than using +
String result = list.stream()
        .map(integer -> integer % 2 == 0 ?
            String.format("%d%s", integer, "g") : String.format("%d%s", integer, "u"))
        .collect(Collectors.joining(","));

However, if I were to implement the 3rd one, I would use simple for-each iteration and StringBuilder that is suitable for the string concatenation:

StringBuilder sb = new StringBuilder();
for (Integer integer: list) {
    sb.append(integer);
    if (integer % 2 == 0) {
        sb.append("g,");
    } else {
        sb.append("u,");
    }
}
String result = sb.toString().substring(0, sb.length() - 1);

... or using a new collection with String.join method ...

List<String> newList = new ArrayList<>();
for (Integer integer: list) {
    String toAdd = integer % 2 == 0 ? 
        String.format("%d%s", integer, "g") : 
        String.format("%d%s", integer, "u");
    newList.add(toAdd);
}
String result = String.join(",", newList);

Upvotes: 2

Related Questions