【问题标题】:How to group the same element in array and sum it in Swift?如何将数组中的相同元素分组并在Swift中求和?
【发布时间】:2017-11-24 03:36:51
【问题描述】:

如何将重复的类别元素过滤到不同的数组中并计算它们的数量?

这是格式,记录来自核心数据。

var record = [Record]()

[<Record:...; data: {accountbook = "MyBook";
                     amount = "10.50";
                     category = "A";
                     id = 1; 
},<Record:...; data: {accountbook = "MyBook";
                     amount = "5.50";
                     category = "B";
                     id = 2;
},<Record:...; data: {accountbook = "MyBook";
                     amount = "4.50";
                     category = "B";
                     id = 3;
}]

我想要什么

var category = ["A", "B"] //success
var total = [10.50, 10.00]

这是我查找类别的方法,它有效,但如何对同一类别进行分组并求和?

var category =[String]()
for categoryObject in record{
    if let categoryItem = categoryObject.category{
        category.append(categoryItem)
    }
}

//I tried this code to group the same category but fail. 

let result = Set(record).map{ category in return record.filter{$0 == category} }

另一种方式是这样。但是如果我有 A-Z 类别呢?它将有很长的代码。有什么方法可以检测到相同的值并将其拆分为不同的数组,以便我可以按类别求和。

categoryFilter = record.filter { $0.category!.contains("A") }

【问题讨论】:

    标签: arrays swift


    【解决方案1】:

    首先按类别对您的记录对象进行分组,例如this

    extension Sequence {
        func group<GroupingType: Hashable>(by key: (Iterator.Element) -> GroupingType) -> [[Iterator.Element]] {
            var groups: [GroupingType: [Iterator.Element]] = [:]
            var groupsOrder: [GroupingType] = []
            forEach { element in
                let key = key(element)
                if case nil = groups[key]?.append(element) {
                    groups[key] = [element]
                    groupsOrder.append(key)
                }
            }
            return groupsOrder.map { groups[$0]! }
        }
    }
    

    然后您将获得基于此类的不同数组

    var records : [Record] = []// your objects
    let distinctRecords = records.group(by: {$0. category})
    

    现在您可以使用 reduce 来计算该类别的值的总和

    for items in distinctRecords{
        let sum = items.reduce(0.0){$0.0 + $1. amount ?? 0.0}// assuming you have float values in your amount
        print(items)// do whatever you want to do with your distinct array
        print(" \(sum)")
    }
    

    【讨论】:

    • 在record.group(by:{$0.category})上,我收到了Cannot convert value of type '(_) -&gt; _' to expected argument type '(Record) -&gt; _'
    • 你的对象数组是这样的吗var records:[record] = []//intialize with objects of record
    【解决方案2】:

    @Wan Jern 我写了一段代码,你可以试试这个。希望它会起作用。

    var category = [String]()
    var totalArr = [CGFloat]()
    for categoryObject in record{
        if let categoryItem = categoryObject.category{
            if !category.contains(categoryItem) {
                category.append(categoryItem)
                totalArr.append(categoryObject.amount)
            } else {
                let index = category.index(of: categoryItem)
                let itemAtIndex = category[index]
                let itemAtIndex = itemAtIndex + categoryObject.amount
                totalArr.insert(itemAtIndex, at: index)
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      你在类模型中有你的记录结构吗?

      就像我从 sqlite 中选择的数据模型:

      //Data model
      import Foundation
      import UIKit
      class scoreModel: NSObject {
          var lessonName:String = String()
          var lessonCode:String = String()
          var creditPoint:Double = Double()
          var totalStudentNumber:Int = Int()
          var teacherName:String = String()
          var semesterName:String = String()
          var scoreValue:String = String()
          var studentCount:Int = Int()
      }
      

      如果答案是肯定的,我们可以使用数组中的指针并重复while循环来手动完成。

      喜欢我的代码:

      let mysql = ""
      let dataArray = SQLiteManager.shareInstance.queryDB(sql:mysql)
      var i = 0
      
      while i<dataArray.count-1
      {
          var scoreArray = [Dictionary<String, Int>]()
          var range = 0
          var test = 0
          test = i
          //print("pointer i is'\(test)'")
      
          while ((dataArray[test]as! scoreModel).lessonCode == (dataArray[test+range]as! scoreModel).lessonCode && (test+range)<dataArray.count-1)
          {
              let key = (dataArray[test+range]as! scoreModel).scoreValue
              let value = (dataArray[test+range]as! scoreModel).studentCount
              var dict: [String: Int] = [String: Int]()
              dict[key] = value
              scoreArray.append(dict)
              //print("working pointer is'\(test+range)'")
              range = range+1
          }
      
          //transfer array
          let model:resultModel = resultModel()
          model.lessonName = (dataArray[test]as! scoreModel).lessonName
          model.lessonCode = (dataArray[test]as! scoreModel).lessonCode
          model.creditPoint = (dataArray[test]as! scoreModel).creditPoint
          model.semesterName = (dataArray[test]as! scoreModel).semesterName
          model.teacherName = (dataArray[test]as! scoreModel).teacherName
          model.totalStudentNumber = (dataArray[test]as! scoreModel).totalStudentNumber
          model.scoreArray = scoreArray
          resultArray.add(model)
          i = i+range
          //print("range is'\(range)'")
      }
      

      【讨论】:

        【解决方案4】:

        Records 设为Hashable,并将“category”作为存根函数中的唯一值

        struct Record: Hashable {
        
            var accountbook = ""
            var category = ""
            var amount = 0.0
            // added from stubs of Hashable
            var hashValue: Int { return category.hashValue }
        
            static func ==(lhs: Record, rhs: Record) -> Bool {
                return lhs.category == rhs.category
            }
        }
        

        然后过滤唯一的类别

        let categories = Set(record).map { $0.category }
        print(categories) // ["B", "A"]
        

        并对每个类别求和

        let totals = categories.map { c in
            record.filter { $0.category == c }.map{ $0.amount }.reduce(0, +)
        }
        print(totals) // get the sums as [10.0, 10.5]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-11-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-22
          • 1970-01-01
          • 2022-01-05
          • 1970-01-01
          相关资源
          最近更新 更多