【问题标题】:Split string into Array of Arrays [closed]将字符串拆分为数组数组[关闭]
【发布时间】:2019-03-30 18:52:48
【问题描述】:

我正在用 Swift 4.2

编写一个 iOS 应用程序

来自服务器的响应是一个字符串,其值由管道字符“|”分隔。它包含许多行值。我想把它拆分成一个子数组。

响应示例:

“001|苹果|红色|002|香蕉|黄色|003|葡萄|紫色”

对于这个例子,输出应该是一个包含 3 个以上水果数组的数组。如果我使用response.componentsSeparatedByString("|"),它会给我一个包含 9 个元素的数组,这是我不想要的。如果我考虑上面的例子,我需要的是一个由 3 个数组组成的数组,还有 3 个元素。

预期输出:

[[001, "apple", "red"], [002, "banana", "yellow"], [003, "grapes", "purple"]]

【问题讨论】:

  • 添加您的期望输出您需要的内容。
  • 你能显示一些代码或OP
  • String 中有一种方法可以用字符串分隔所有内容(如管道字符)。之后,由您将其转换为“子数组”,但我们不知道它应该是什么样子。是否需要保留数字等。
  • 解释你尝试了什么以及为什么它不起作用,你使用的是swift还是objective-c?请删除不相关的标签
  • 你能要求 API 给你一些漂亮的 JSON 吗? :)

标签: ios swift


【解决方案1】:

如果我得到了正确的结果,那么此代码将满足您的要求:

extension Array {
    func chunked(into size: Int) -> [[Element]] {
        return stride(from: 0, to: self.count, by: size).map {
            Array(self[$0 ..< Swift.min($0 + size, self.count)])
        }
    }
}

let src = "001|apple|red|002|banana|yellow|003|grapes|purple"
let result = src.split(separator: "|").map(String.init).chunked(into: 3)
// result = [["001", "apple", "red"], ["002", "banana", "yellow"], ["003", "grapes", "purple"]]

如果您知道结果子数组的预期大小,这将起作用

如果数组元素的类型为 String.SubSequence 对您来说没问题,您也可以从最后一行删除 .map(String.init)

【讨论】:

  • 很遗憾,您的解决方案不适用于一个子组中的动态项目数。
  • 非常感谢,什么是元素类型?
  • @ManWithBear 没有这样的要求。也没有信息表明每个子数组都以数字开头,所以我只是做了一个假设
  • @AntonFilimonov 公平点
【解决方案2】:
  1. | 字符分割字符串
  2. 然后在结果数组的最后一个子数组中追加不是数字的元素
  3. 如果元素是数字,则将新子数组添加到结果数组中
  4. 重复 2-3 直到完成
let input = "001|apple|red|002|banana|yellow|003|grapes|purple"
let result: [[String]] = input
    .split(separator: "|")
    .reduce(into: []) { result, string in
        guard let _ = Int(string) else {
            result[result.count - 1].append(String(string))
            return
        }
        result.append([])
    }
/// result: [["apple", "red"], ["banana", "yellow"], ["grapes", "purple"]]

如果你也想坚持001,那么将result.append([])更改为result.append([String(string)])

[["001", "apple", "red"], ["002", "banana", "yellow"], ["003", "grapes", "purple"]]

重要

此解决方案希望您的字符串以数字开头,否则会崩溃。
如果您不能保证您的字符串以数字开头,您需要手动检查该数组在保护块中是否为空。

【讨论】:

  • 您在此解决方案中的分块大小在哪里?
  • @SheikhAtif 这个解决方案根本不需要块大小。它总是按数字分割,因此您可以在一个子数组中拥有动态数量的元素
  • 实际上,真正的响应在一行中有 100 多个元素,包括 .数字类型很多地方
  • 如果您总是在一行中拥有相同数量的项目,那么@AntonFilimov 解决方案将更容易且足够
【解决方案3】:

感谢OOPer's extension,借助正则表达式,您可以做这样的事情

添加基于正则表达式模式拆分字符串的字符串扩展。

extension String {
    func split(usingRegex pattern: String) -> [String] {
        //### Crashes when you pass invalid `pattern`
        let regex = try! NSRegularExpression(pattern: pattern)
        let matches = regex.matches(in: self, range: NSRange(0..<utf16.count))
        let ranges = [startIndex..<startIndex] + matches.map{Range($0.range, in: self)!} + [endIndex..<endIndex]
        return (0...matches.count).map { String(self[ranges[$0].lowerBound..<ranges[$0+1].lowerBound]) }
    }
}

然后根据模式[0-9]{3}连续3个数字拆分您的字符串。

let str = "001|apple|red|002|banana|yellow|003|grapes|purple|004|this|is|a|test|one|005|so|is|this"
let pattern = "[0-9]{3}"
let result = str.split(usingRegex: pattern)

var all:[[String]] = []
for row in result {
    let split = row.split(separator: "|").map({ (substring) in
        return String(substring)
    })
    if split.count != 0 {
        all.append(split)
    }
}

dump(all)

我在操场上对此进行了测试,得到了以下结果:

▿ 5 elements
  ▿ 3 elements
    - "001"
    - "apple"
    - "red"
  ▿ 3 elements
    - "002"
    - "banana"
    - "yellow"
  ▿ 3 elements
    - "003"
    - "grapes"
    - "purple"
  ▿ 6 elements
    - "004"
    - "this"
    - "is"
    - "a"
    - "test"
    - "one"
  ▿ 4 elements
    - "005"
    - "so"
    - "is"
    - "this"

如果您决定要从结果数组中排除 ID,您可以将扩展返回修改为以下内容:

return (0...matches.count).map { String(self[ranges[$0].upperBound..<ranges[$0+1].lowerBound]) }

这将切换返回范围以使用upperBound 而不是lowerBound

【讨论】:

  • OP 希望在一行中有数字,并且看起来在一行中也有静态的项目数
【解决方案4】:

您可以使用 String 方法 enumerateSubstrings in range 使用 byWords 选项,检查字符串是否为整数,如果是,则将带有该字符串的新数组附加到结果中,否则将单词附加到最后一个结果数组中:

let string = "001|apple|red|002|banana|yellow|003|grapes|purple"
var result: [[Substring]] = []
string.enumerateSubstrings(in: string.startIndex..., options: .byWords) { _, range, _, _ in
    let word = string[range]
    if let _ = Int(word) {
        result.append([word])
        // or just a new empty array
        // result.append([])
    } else {
        result[result.index(before: result.endIndex)].append(word)
    }
}

print(result)   // "[["001", "apple", "red"], ["002", "banana", "yellow"], ["003", "grapes", "purple"]]\n"

【讨论】:

    【解决方案5】:

    基本方法

    let str = "001|apple|red|002|banana|yellow|003|grapes|purple"
    let components = str.components(separatedBy: "|")
    let chunkSize = 3
    let loopCount = components.count/chunkSize
    
    var packages: [Array<String>] = []
    for index in  0..<loopCount {
        /// Starting index
        let numIndex = index * chunkSize
    
        /// Get the subarray of range
        let package = Array(components[numIndex..<(numIndex+chunkSize)])
        packages.append(package)
    }
    
    print(packages)
    

    输出:

    [[“001”、“苹果”、“红”]、[“002”、“香蕉”、“黄”]、[“003”、“葡萄”、“紫”]]

    【讨论】:

    • 改为使用步幅
    • 答案就是这么简单!谢谢
    • 实际上真正的响应在一行中有 100 多个元素,例如我只显示了数字、水果、颜色。
    • 然后将 3 替换为 100 :)
    • 我需要根据这个解决方案制作100多个变量。
    【解决方案6】:

    好的,你可以递归地做到这一点

    let input = "001|apple|red|002|banana|yellow|003|grapes|purple"
    
    let array = input.components(separatedBy: "|")
    
    
    // Get Chunks from array
     extension Array {
          func getFirstElements(upTo position: Int) -> Array<Element> {
             let arraySlice = self[0 ..< position]
             return Array(arraySlice)
          }
      }
    
    func recersivelyGetArray (array:[String], slice:inout [[String]]) {
    
      guard !array.isEmpty else{
        return
      }
    
      var copyArray = array
    
      var chunkSize = 3
      if  array.count >= 3 {
        chunkSize = 3
      } else {
        chunkSize = array.count
      }
      let threeElements =  copyArray.getFirstElements(upTo: chunkSize)
      slice.append(threeElements)
    
      copyArray.removeFirst(chunkSize)
    
      recersivelyGetArray(array: copyArray, slice: &slice)
    
    
    }
    
    var inoutResult = [[String]]()
    
    recersivelyGetArray(array: array, slice: &inoutResult)
    
    print(inoutResult) 
    

    输出

    案例 1 用于输入

    let input = "001|apple|red|002|banana|yellow|003|grapes|purple"
    

    [[“001”、“苹果”、“红”]、[“002”、“香蕉”、“黄”]、[“003”、“葡萄”、“紫”]]

    案例 2 用于输入

    let input = "001|apple|red|002|banana|yellow|003|grapes"
    

    [[“001”、“苹果”、“红”]、[“002”、“香蕉”、“黄”]、[“003”、“葡萄”]]

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-01
      • 2020-06-15
      • 1970-01-01
      • 2016-06-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多