在Java 8中以惯用方式枚举对象流

时间:2017-02-14 14:20:04

标签: java java-8 java-stream enumeration

如何使用Java 8流方法(例如,对于数组Stream<T>,以惯用方式枚举T将每个T[] values实例映射到唯一整数,从而创建Map<T,Integer>其中Map.get(values[i]) == i评估为true)?

目前,我定义了一个匿名类,该类增加int字段以便与Collectors.toMap(..)方法一起使用:

private static <T> Map<T, Integer> createIdMap(final Stream<T> values) {
    return values.collect(Collectors.toMap(Function.identity(), new Function<T, Integer>() {

        private int nextId = 0;

        @Override
        public Integer apply(final T t) {
            return nextId++;
        }

    }));
}

但是,使用Java 8流API是否没有更简洁/更优雅的方法? - 如果可以安全地并行化,则可获得奖励积分。

3 个答案:

答案 0 :(得分:5)

如果存在重复元素,您的方法将失败。

除此之外,您的任务需要可变状态,因此可以使用Mutable reduction来解决。当我们填充地图时,我们可以简单地使用地图的大小来获取未使用的ID。

更棘手的部分是合并操作。以下操作只是重复右图的分配,它将处理潜在的重复。

distinct()

如果我们依赖于唯一元素,或者插入明确的private static <T> Map<T, Integer> createIdMap(Stream<T> values) { return values.distinct().collect(HashMap::new, (m,t) -> m.put(t,m.size()), (m1,m2) -> { int leftSize=m1.size(); if(leftSize==0) m1.putAll(m2); else m2.forEach((t,id) -> m1.put(t, leftSize+id)); }); } ,我们可以使用

var apiUrl : String
var alamoFireManager:Manager!
var configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
init(apiUrl : String){
        self.apiUrl = apiUrl
        configuration.timeoutIntervalForRequest = 30.0
        alamoFireManager = Alamofire.Manager(configuration: configuration)
    }
print(apiUrl)
alamoFireManager.request(.GET, apiUrl, encoding: .JSON).validate(contentType: ["application/json"]) .responseJSON { response in
            print(response.result.value)
            switch response.result{
            case .Success:
                if let value = response.result.value{
                    let json = JSON(value)
                    print (json)
                    callback.onResponse(value) // this is where my value is sent
                }
            case .Failure(let error):
                print(error.localizedDescription)
            }
        }

答案 1 :(得分:4)

我会这样做:

private static <T> Map<T, Integer> createIdMap2(final Stream<T> values) {
    List<T> list = values.collect(Collectors.toList());
    return IntStream.range(0, list.size()).boxed()
            .collect(Collectors.toMap(list::get, Function.identity()));
}

为了起因或平行,可将其更改为

   return IntStream.range(0, list.size()).parallel().boxed().
                (...)

答案 2 :(得分:0)

比较在Andremoniy提供的解决方案中首先将输入流转换为List。我宁愿以不同的方式做到这一点,因为我们不知道“toList()”和“list.get(i)”的成本,并且没有必要创建一个额外的List,它可能小或者更大

private static <T> Map<T, Integer> createIdMap2(final Stream<T> values) {
    final MutableInt idx = MutableInt.of(0); // Or: final AtomicInteger idx = new AtomicInteger(0);        
    return values.collect(Collectors.toMap(Function.identity(), e -> idx.getAndIncrement()));
}

无论问题如何,我认为将流作为参数传递给方法是一种糟糕的设计。