【问题标题】:It is possible to use array reduce concept from swift in objective c?可以在目标 c 中使用 swift 中的数组减少概念吗?
【发布时间】:2016-03-22 17:25:06
【问题描述】:

我在 Swift 中有这行代码:

let graphPoints:[Int] = [4, 2, 6, 4, 5, 8, 3]

let average = graphPoints.reduce(0, combine: +) / graphPoints.count

是否可以将这行代码“翻译”成目标 c 代码?

reduce combine 概念的工作原理对我来说不是很清楚。我读过它,但仍然不清楚。

我从本教程中获取了代码:http://www.raywenderlich.com/90693/modern-core-graphics-with-swift-part-2

请帮忙。谢谢。

【问题讨论】:

  • graphPoints 数组包含什么类型?
  • 猜:average = [graphView.graphPoints valueForKeyPath: @"@sum.self"](或者可能是@avg而不是@sum)。
  • 数组为:var graphPoints:[Int] = [4, 2, 6, 4, 5, 8, 3],包含 int 对象。

标签: ios arrays swift reduce


【解决方案1】:

假设您有一些 NSNumbers 存储在 NSArray 中,您可以使用这个 KVC 集合运算符:

NSArray *someNumbers = @[@0, @1.1, @2, @3.4, @5, @6.7];
NSNumber *average = [someNumbers valueForKeyPath:@"@avg.self"];

【讨论】:

    【解决方案2】:

    对于 Objective-C,我会将高阶函数添加到此答案列表中:https://github.com/fanpyi/Higher-Order-Functions

    #import <Foundation/Foundation.h>
    typedef id (^ReduceBlock)(id accumulator,id item);
    @interface NSArray (HigherOrderFunctions)
    -(id)reduce:(id)initial combine:(ReduceBlock)combine;
    @end
    
    #import "NSArray+HigherOrderFunctions.h"
    @implementation NSArray (HigherOrderFunctions)
    -(id)reduce:(id)initial combine:(ReduceBlock)combine{
        id accumulator = initial;
        for (id item in self) {
            accumulator = combine(accumulator, item);
        }
        return accumulator;
    }
    @end
    

    示例:

       NSArray *numbers = @[@5,@7,@3,@8];
        NSNumber *sum = [numbers reduce:@0 combine:^id(id accumulator, id item) {
            return @([item intValue] + [accumulator intValue]);
        }];
        NSNumber *multiplier = [numbers reduce:@1 combine:^id(id accumulator, id item) {
            return @([item intValue] * [accumulator intValue]);
        }];
        NSLog(@"sum=%@,multiplier=%@",sum,multiplier);
    

    【讨论】:

      【解决方案3】:

      reduce 函数在 Objective-C 中不是标准的。不过,您可以将其实现为 NSArray 的扩展。

      在您的情况下,您在 Swift 中有一个 Int 数组。你不能在 Objective-C 中拥有它,你需要一个 NSNumber 的数组。

      这是reduce 的实现,应该适用于您的情况:

      @implementation NSArray (Helpers)
      
      - (NSInteger)reduceInt:(NSInteger)initial combine:(NSInteger (^)(NSInteger acum, NSInteger element))block {
          if (!self) {
              return initial;
          }
      
          NSInteger acum = initial;
          for (id element in self) {
              if ([element isKindOfClass:[NSNumber class]]) {
                  acum = block(acum, [(NSNumber *)element integerValue]);
              }
          }
      
          return acum;
      }
      
      @end
      

      您可以将它与您的数组一起使用,如下所示:

      NSArray *a = @[@1, @2, @3];
      NSInteger result = [a reduceInt:0 combine:^NSInteger(NSInteger acum, NSInteger element) {
          return acum + element;
      }];
      

      【讨论】:

      • 我认为reduce 如果没有泛型类型就没有多大意义。
      • @Sulthan 好吧,您可以使用ids 实现reduce,这足以在您的代码中使用。当然,拥有泛型会更好。
      • AFAICT, if (!self) 检查不是必需的——它是一个实例方法,所以必须在 self 上调用它。因此,self始终不是nil
      【解决方案4】:

      如何将 reduce 转换为 ObjC(或者更好地说是如何解决 Objective C 中的“普通问题”)由 André Slotta 完美回答。快速减少远不止于此。我会试着回答你问题的第二部分,这个概念是如何在 swift 中起作用的

      func reduce<T>(initial: T, @noescape combine: (T, Self.Generator.Element) throws -> T) rethrows -> T  
      

      返回结果 重复调用组合与初始化为的累积值 初始和 self 的每个元素,依次,即返回 结合(结合(...结合(结合(初始,自我[0]), self[1]),...self[count-2]), self[count-1]).

      let arr: Array<Int> = [1,2,3,4,5]
      let sum = arr.reduce(0) { (sum, i) -> Int in
          return sum + i
      }
      print(sum) // 15
      
      // this is an quasi equivalent of
      var sum1 = 0 // ..... reduce(0)....
      arr.forEach { (elementValue) -> Void in
          sum1 = sum1 + elementValue   // ...{ return sum + i }
      }
      print(sum1) // 15 reduce function will return accumulated inital value
      
      // reduce is part of SequenceType protocol, that is why
      
      let arr1 = ["H","e","l","l","o"," ","w","o","r","l","d"]
      let str = arr1.reduce("") { (str, s) -> String in
          str + s
      }
      // works the same way
      print(str) // "Hello world"
      
      // let have a litle bit more complex example, to see how powerful, useful and easy to use reduce can be
      let dict = arr1.reduce([:]) { (var dict, s) -> Dictionary<Int,String> in
          let i = dict.count
          dict.updateValue(s, forKey: i+1)
          return dict
      }
      print(dict) // [11: "d", 10: "l", 2: "e", 4: "l", 9: "r", 5: "o", 6: " ", 7: "w", 3: "l", 1: "H", 8: "o"]
      

      【讨论】:

        【解决方案5】:

        编写一个 NSArray 扩展

        - (NSInteger)reduceStart:(NSInteger)start combine:(NSInteger(^)(NSInteger x, NSInteger y))combine {
            for (NSNumber* n in self) {
                if ([n isKindOfClass:[NSNumber class]]) {
                    start = combine (start, n.integerValue);
                }
            }
            return start;
        }
        

        纠正我犯的所有错误,就是这样。只是不如 Swift 灵活。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-02-25
          • 2016-06-14
          • 2022-10-14
          • 1970-01-01
          • 2016-03-13
          • 1970-01-01
          • 2022-07-27
          相关资源
          最近更新 更多