【问题标题】:How to auto increment the key of a hashmap using collectors and stream in java 8如何在 Java 8 中使用收集器和流自动增加哈希映射的键
【发布时间】:2018-06-26 16:24:32
【问题描述】:

我是 Java 8 的新手:StreamsCollectors 类。

我正在读取一个文件,其内容需要保存在LinkedHashMap<Integer, String> 中,其中<keys> 是文件的行号,其<values> 是每一行的内容,可敬。

在这里,我想使用Stream 概念,但我无法使用Collectors.toMap 自动递增<keys>,需要将其保存在LinnkedHashMap 对象中。相反,我得到了例外。

以下是我正在尝试的代码:

List<String> list = new ArrayList<>();
Integer count = 0;

try (BufferedReader br = Files.newBufferedReader( Paths.get( fileName ) )) {
    // br returns as stream and convert it into a List
    list = br.lines().collect( Collectors.toList() );
}
catch ( IOException e ) {
    e.printStackTrace();
}

list.forEach( System.out::println );

Map<Integer, String> fileNumWithContentMapper = list.stream()
        .collect( Collectors.toMap( n->n+1,s1->s1));

【问题讨论】:

  • 你想创建一个 HashMap 键,从 0 到 n 连续,取决于条目的多少? Array 或 ArrayList 还没有的 HashMap 有什么用?它的键正是那个
  • 您遇到了哪些例外情况?你能用这些信息更新你的问题吗?

标签: java java-8 java-stream collectors


【解决方案1】:

有很多方法可以做到这一点。但在这里我会解释我的方式:

1。设置IntStream 对象的大小。

首先,只要您有一个List&lt;E&gt; 对象(即E 可能是StringIntegersObjects 等),您可以使用@987654328 将其转换为Map&lt;Integer, E&gt; @ 班级。此类是支持顺序和并行聚合操作的原始 int 值元素序列。这意味着就像一个巨大的柜台。如果我们已经有一个计数器,我们需要设置一些限制,IntStream.range(int start, int end) 方法将帮助我们。此方法将以增量 1 的增量返回从start(包括)到end(不包括)的顺序排列的IntStream。因此,如果您想创建一个大小与我们的List 相同的IntStream,请使用这个:

List<Integer> numbers = Arrays.asList(4, 5, 4, 3);
IntStream stream = IntStream.range(0, numbers.size); 

2。根据IntStream对象准备Stream对象。

现在,我们有一个与您的List&lt;E&gt; 一样大小的计数器,但我们需要一个Map&lt;Integer, E&gt;。好吧,现在我们将使用IntStream.boxed()。这个方法返回一个Stream,由这个流的元素组成,每个元素都装箱到一个Integer。这是Stream&lt;Integer&gt;。我们快完成了。

Stream<Integer> streamBoxed = stream.boxed();

3。将Stream 对象转换为Map 对象

最后,我们可以使用Stream.collect() 方法创建地图。此方法对此流的元素执行可变归约操作。如果我们没有Collectors.toMap() 方法的帮助,这种减少会很复杂。此收集器可用于将 Stream 元素收集到 Map 实例中。为此,我们需要提供两个函数:keyMappervalueMapperkeyMapper 将用于从Stream 元素中提取Map 键,valueMapper 将用于提取与给定&lt;key&gt; 关联的&lt;value&gt;。对于我们的示例,我们将使用Map&lt;Integer, Integer&gt;keyMapper 将是我们可以提取的steamBoxed 流的值,使用i -&gt; ivalueMapper 应该是numbers 列表的值,我们将使用i -&gt; numbers.get(i) 得到这些值,如下所示:

Map<Integer, Integer> result = streamBoxed.collect(Collectors.toMap(i -> i, i -> numbers.get(i)))

4。合并所有步骤

这三个部分可以在这个简单的代码中组合在一起:

List<Integer> numbers = Arrays.asList(4, 5, 4, 3);

Map<Integer, Integer> result = IntStream
        .range(0, numbers.size); // IntStream 
        .boxed(); // Stream<Integer>
        .collect(Collectors.toMap(i -> i, i -> numbers.get(i))) // Map<Integer, Integer>

另外,你会发现有些作者更喜欢将Function.identity() 方法用作keyMapper,而将numbers::get lambda 表达式用作valueMapper他们为什么使用这些表达方式?只是为了偏好。 Function.identity() 方法将始终返回相同的实例。因此,使用Function.identity() 而不是i -&gt; i 可能会节省一些内存。但是,i -&gt; iFunction.identity() 更具可读性,但因为创建了自己的实例并具有不同的实现类会消耗更多内存。 :: lambda 表达式只是一个方法引用捕获。

但是,我如何将它应用到我的解决方案中?

嗯,像这样:

final List<String> list;

...
// list initialization;
list = br.lines().collect(Collectors.toList());
...

Map<Integer, String> fileNumWithContentMapper = IntStream
        .range(0, list.size()) // IntStream 
        .boxed() // Stream<Integer>
        .collect(Collectors.toMap(i -> i, i -> list.get(i))); // Map<Integer, String>
选择
final List<String> list;

...
// list initialization;
list = br.lines().collect(Collectors.toList());
...

Map<Integer, String> fileNumWithContentMapper = IntStream
        .range(0, list.size()) // IntStream 
        .boxed() // Stream<Integer>
        .collect(Collectors.toMap(Function.identity(), list::get)) // Map<Integer, String>

【讨论】:

  • 用恰当的例子解释得很好。
【解决方案2】:

试试这个代码:

public static void main(String[] args)  {
    List<String> list = Arrays.asList("A", "B", "C");
    list.forEach( System.out::println );

    AtomicInteger i = new AtomicInteger(0);
    Map<Integer, String> fileNumWithContentMapper = list.stream()
                .collect( Collectors.toMap( n->i.incrementAndGet(),s1->s1));

    System.out.println(fileNumWithContentMapper);
}

【讨论】:

    【解决方案3】:

    你可以使用IntStream.range:

    IntStream.range(0, list.size())
             .boxed()
             .collect(Collectors.toMap(Function.identity(), i -> list.get(i)));
    

    另一种选择是使用LineNumberReader API。

    【讨论】:

      【解决方案4】:

      假设您有List,如下所示:

      List<String> list =  Arrays.asList("Vishwa","Ram","Mohan","Sohan");
      

      现在你想要输出就像下面

      0  Vishwa
      1  Ram
      2  Mohan
      3  Sohan
      

      public class Someclass{
      static int j=0;
      static int count(int de){
          return de++;
      }
          public static void main(String[] args) {
           List<String> list =  Arrays.asList("Vishwa","Ram","Mohan","Sohan");
              Map<Integer,String> map;
              map = list.stream().collect(Collectors.toMap(s->{count(j);return j++;}, Function.identity()));
              map.forEach((k,v)-> {
                               System.out.print(k+"  ");
                               System.out.println(v);
          });
          }
      }
      

      【讨论】:

        【解决方案5】:
        Stream.of("A", "B", "C").collect(TreeMap<Integer, String>::new
            ,(map, element) -> map.put(Optional.ofNullable(map.lastEntry()).map(e -> e.getKey() + 1).orElse(1), element)
            ,(m1, m2) -> {})
            .forEach((i, e) -> System.out.println(i + " " + e));
        

        打印:

        1 A 
        2 B
        3 C
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-09-22
          • 1970-01-01
          • 1970-01-01
          • 2018-10-13
          • 1970-01-01
          • 2014-09-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多