2017-02-08 7 views
1

У меня есть список со словами (языки программирования), и я хочу выяснить, какая буква в алфавите присутствует в этих словах, а затем суммировать общую строку длина этих слов и, в конце концов, возвращает одну букву, которая возвращает самую длинную строку, соответствующую этим словам. Вот то, что у меня есть до сих пор, и я почти не буду дальше.возвращает сумму строк, где присутствует буква - с использованием потоков

Это упражнение во мне, пытаясь лучше понять потоки Java.

package com.example; 

import org.junit.Test; 
import java.util.ArrayList; 
import java.util.List; 
import java.util.function.Supplier; 
import java.util.stream.IntStream; 
import java.util.stream.Stream; 

public class DemoApplicationTests { 

    @Test 
    public void argh() { 

     List<String> list = new ArrayList<>(); 
     list.add("java"); 
     list.add("php"); 
     list.add("python"); 
     list.add("perl"); 
     list.add("c"); 
     list.add("lisp"); 
     list.add("c#"); 

     Supplier<Stream<String>> streamSupplier =() -> list.stream(); 
     IntStream.range('a', 'z').forEach(i -> { 
       int strlen = streamSupplier.get() 
        .filter(k -> { 
          char ch = (char) i; 
          return k.contains("" + ch); 
         } 
        ) 
        .map(s -> s.length()) 
        .mapToInt(Integer::new) 
        .sum(); 
       System.out.println((char) i + " : " + strlen); 
      } 
     ); 
    } 
} 

Конечный результат (результат), я бы ожидать, это просто что-то вроде «р: 17»

Как символ «р» присутствует в слова PHP, Python, Perl, сюсюкать это подводит те слова и возвращает StringLength из 17.

Предпочтительно в

map<String,int> with the size of 1 

или что-то, содержащие только самую длинную строку.

Вот некоторые псевдокоды о том, как я написал бы ее в «простом» ява:

int previousSum = 0; 
for (string ch in ('a' to 'z')) { 
    int stringlengthSum =  findallMatchesInListandSumStringlength(stringlist,ch); 
if (stringlengthSum > previousSum) { 
    previousSum = stringLengthSum; 
    longestCharacter = ch; 
} 
} 
System.out.println("The longest sum is: " + previousSum + " by the character: " + longestcharacter); 
+2

Какой результат вы ожидаете? – assylias

+0

Можете ли вы описать результат, который хотите получить для этого конкретного примера? Не совсем понятно, что вы хотите сделать. – Andremoniy

+1

выглядит хорошо для меня, в чем ваш вопрос? возможно, это лучше подходит для CodeReview? –

ответ

1

мне пришлось немного изменить и оптимизировать код. Окончательное решение будет:

Map.Entry<Integer, Integer> max = IntStream.range('a', 'z').boxed().collect(Collectors.toMap(i -> i, i -> list.stream() 
     .filter(k -> k.contains("" + (char) i.intValue())) 
     .map(String::length) 
     .mapToInt(Integer::new) 
     .sum())) 
     .entrySet().stream() 
     .max((e1, e2) -> e1.getValue().compareTo(e2.getValue())).get(); 

System.out.println((char)max.getKey().intValue() + ":" + max.getValue()); 

Изменения:

1) конвертировать IntStream в Stream<Integer> для возможности собирать карту из него

2) собирают пары: INT значение символа -> сумма слов с этим символом

и по крайней мере 3) найти запись карты с максимальным элементом в нем

+0

, по-видимому, я могу это сделать, согласно IntelliJ: ".max (Comparator.comparing (Map.Entry :: getValue)). Get();" Спасибо! – OddBeck

+1

Если вы заботитесь о производительности, вы можете заменить '.filter (k -> k.contains (" "+ (char) i.intValue()))' с '.filter (k -> k.indexOf (i)> = 0) 'и' .map (String :: length) .mapToInt (Integer :: new) 'с' .mapToInt (String :: length) '. Обратите внимание, что более эффективные альтернативы еще проще. И '.max ((e1, e2) -> e1.getValue(). CompareTo (e2.getValue()))' можно упростить до '.max (Map.Entry.comparingByValue())'. – Holger

1

Вы были довольно близки, вам просто не хватает порядка потока.

Чтобы сделать весь заказ немного легче, вы можете создать специальный класс:

class CharacterLengthSumResult implements Comparable<CharacterLengthSumResult> { 
     final char c; 
     final int sum; 

     CharacterLengthSumResult(char c, int sum) { 
      this.c = c; 
      this.sum = sum; 
     } 

     @Override 
     public int compareTo(CharacterLengthSumResult o) { 
      return Integer.compare(o.sum, sum); 
     } 
    } 

Тогда потоковая логика становится:

Optional<CharacterLengthSumResult> first = IntStream.range('a', 'z').mapToObj(i -> { 
      String c = ((char) i) + ""; 
      int sum = list.stream().filter(s -> s.contains(c)).mapToInt(String::length).sum(); 
      return new CharacterLengthSumResult((char)i, sum); 
     }).sorted().findFirst(); 

     if (first.isPresent()) { 
      System.out.println(first.get().c + " -> " + first.get().sum); 
     } 

Если вы хотите, чтобы все это как карту, вы можете расширить сортировку с помощью коллектора:

...sorted().collect(Collectors.toMap(s -> s.c, s -> s.sum)); 
+0

Hm ... выглядит сложнее – Andremoniy

+0

@Andremoniy hm выглядит как чистый код, а не взломать записи на карте. –

+0

* взломать записи на карте * ??? :))) ха-ха-ха, где вы видите взлом? Если вы не знаете, как готовить поток, это не значит, что это «взлом» :) Извините – Andremoniy