使用Stream lambda将CSV字符串值转换为Hashmap

时间:2015-07-15 13:52:51

标签: java dictionary java-8 java-stream

我正在尝试使用Java 8 Streams API从CSV字符串值中获取HashMap<String,String>。我可以获取值等,但如何将List的索引添加为HashMap中的键。

(HashMap<String, String>) Arrays.asList(sContent.split(",")).stream()
        .collect(Collectors.toMap(??????,i->i );

所以我的地图将包含Key,Value,如下所示。

0->Value1
1->Value2
2->Value3
...

使用普通Java我可以轻松完成,但我想使用JAVA 8流API。

3 个答案:

答案 0 :(得分:2)

这是一个奇怪的要求。当您致电Arrays.asList(sContent.split(","))时,您已经拥有了将int个数字映射到String的数据结构。结果是List<String>,您可以使用.get(intNumber)来调用Map<Integer,String>来获取所需的值...

但是,如果它确实必须是Map并且您想要使用流API,则可以使用

Map<Integer,String> map=new HashMap<>();
Pattern.compile(",").splitAsStream(sContent).forEachOrdered(s->map.put(map.size(), s));

为了解释它,Pattern.compile(separator).splitAsStream(string)Arrays.stream(string.split(separator))的作用相同,但不创建中间数组,所以最好。而且你不需要一个单独的计数器,因为地图本身维护着这样一个计数器,它的大小。

上面的代码用于创建这样的地图ad-hoc的最简单的代码,而干净的解决方案将避免流操作本身之外的可变状态并在完成时返回新的映射。但清洁解决方案并不总是最简洁:

Map<Integer,String> map=Pattern.compile(",").splitAsStream(sContent)
    .collect(HashMap::new, (m,s)->m.put(m.size(), s),
        (m1,m2)->{ int off=m1.size(); m2.forEach((k,v)->m1.put(k+off, v)); }
    );

虽然collect的前两个参数定义了与前一个解决方案类似的操作,但最大的障碍是第三个参数,一个仅在请求并行处理时使用的函数,尽管单个csv行不太可能从中获益并行处理。但是不支持省略它。如果使用,它将合并两个映射,这两个映射是两个并行操作的结果。由于两者都使用了自己的计数器,因此必须通过添加第一张地图的大小来调整第二张地图的索引。

答案 1 :(得分:1)

您可以使用以下方法获取所需的输出

  private Map<Integer, String> getMapFromCSVString(String csvString) {
        AtomicInteger integer = new AtomicInteger();
        return Arrays.stream(csvString.split(","))
                .collect(Collectors.toMap(splittedStr -> integer.getAndAdd(1), splittedStr -> splittedStr));
    }

我在下面写了测试来验证输出。

 @Test
    public void getCsvValuesIntoMap(){
        String csvString ="shirish,vilas,Nikhil";
        Map<Integer,String> expected = new HashMap<Integer,String>(){{
            put(0,"shirish");
            put(1,"vilas");
            put(2,"Nikhil");

        }};
        Map<Integer,String> result = getMapFromCSVString(csvString);
        System.out.println(result);
        assertEquals(expected,result);

    }

答案 2 :(得分:0)

您可以创建一系列索引,如下所示:

<table st-table="rowCollection" class="table">
    <thead>
    <tr>
        <th></th>
        <th st-sort="firstName">first name</th>
        <th st-sort="lastName">last name</th>
        <th st-sort="birthDate">birth date</th>
        <th st-sort="balance">balance</th>
        <th>email</th>
    </tr>
    </thead>
    <tbody>
    <tr ng-repeat="row in rowCollection">
        <td cs-select="row"></td>
        <td>{{row.firstName | uppercase}}</td>
        <td>{{row.lastName}}</td>
        <td>{{row.birthDate | date}}</td>
        <td>{{row.balance | currency}}</td>
        <td><a ng-href="mailto:{{row.email}}">email</a></td>
    </tr>
    </tbody>
</table>


   app.controller('customCtrl', ['$scope', function (scope) {
        scope.rowCollection = [
            {firstName: 'Laurent', lastName: 'Renard', birthDate: new Date('1987-05-21'), balance: 102, email: 'whatever@gmail.com'},
            {firstName: 'Blandine', lastName: 'Faivre', birthDate: new Date('1987-04-25'), balance: -2323.22, email: 'oufblandou@gmail.com'},
            {firstName: 'Francoise', lastName: 'Frere', birthDate: new Date('1955-08-27'), balance: 42343, email: 'raymondef@gmail.com'}
        ];
    }]);
    app.directive('csSelect', function () {
        return {
            require: '^stTable',
            template: '<input type="checkbox"/>',
            scope: {
                row: '=csSelect'
            },
            link: function (scope, element, attr, ctrl) {

                element.bind('change', function (evt) {
                    scope.$apply(function () {
                        ctrl.select(scope.row, 'multiple');
                    });
                });

                scope.$watch('row.isSelected', function (newValue, oldValue) {
                    if (newValue === true) {
                        element.parent().addClass('st-selected');
                    } else {
                        element.parent().removeClass('st-selected');
                    }
                });
            }
        };
    });