快速查找字符串数组的所有组合

Posted

技术标签:

【中文标题】快速查找字符串数组的所有组合【英文标题】:Find all combination of string array in swift 【发布时间】:2017-01-02 18:53:43 【问题描述】:

我有一个字符串数组,我想找到其元素的所有可能组合

例如:

数组 = [A,B,C,D]

应该产生结果:

[A,AB,AC,AD,ABC,ABD,ACD,ABCD,B,BC,BD,BCD,C,CD,D]

这是我的逻辑:

  var array = ["A", "B", "C","D"]
  var list = [String]()
  for i in 0..<array.count
    let c = array[i]
    list.append(c)
    var d = c
    for count in 1..<array.count

        if i+count < array.count
            for j in i+count..<array.count
                var a = d
                a.appendContentsOf(array[j])
                print("a : \(a)")
                list.append(a)
            

        
        d = c
        d.appendContentsOf(array[count])
        print("d : \(d)")
    

print(list.description)

它的输出是:

[“A”、“AB”、“AC”、“AD”、“ABC”、“ABD”、“ACD”、“B”、“BC”、“BD”、“BBD” , “C”、“CD”、“D”]

此输出缺少 ABCD 并且错误地将 BCD 打印为 BBD

任何人请通过增强我的代码或为此建议您自己的逻辑来帮助我。

【问题讨论】:

***.com/questions/33021064/… 我之前已经搜索过了,这个链接的问题是排列而不是组合(我只想要 ABCD 而不是 ABCD,ACBD ...) 您的结果重复例如B 和 C。我认为这不是故意的? 哦,是的,这是一个错字……我正在编辑我的问题……谢谢 【参考方案1】:

@yannick 的答案非常接近。

通过计算您的集合的一个幂集,您可以获得所有可能的子集(包括您的原始集和空集)。

一旦你获得了幂集,你所要做的就是将子集连接成一个字符串,以获得你正在寻找的结果。

这是完整的解决方案(以及更新的代码和大量 cmets):

extension Array 
    var powerset: [[Element]] 
        guard count > 0 else 
            return [[]]
        

        // tail contains the whole array BUT the first element
        let tail = Array(self[1..<endIndex])

        // head contains only the first element
        let head = self[0]

        // computing the tail's powerset
        let withoutHead = tail.powerset

        // mergin the head with the tail's powerset
        let withHead = withoutHead.map  $0 + [head] 

        // returning the tail's powerset and the just computed withHead array
        return withHead + withoutHead
    


let myArray = ["A", "B", "C", "D"]
print(myArray.powerset) // -> [["D", "C", "B", "A"], ["C", "B", "A"], ["D", "B", "A"], ["B", "A"], ["D", "C", "A"], ["C", "A"], ["D", "A"], ["A"], ["D", "C", "B"], ["C", "B"], ["D", "B"], ["B"], ["D", "C"], ["C"], ["D"], []]

// joining the subsets
let myResult = myArray.powerset.map  $0.sort().joinWithSeparator("") 
print(myResult) // -> ["A", "AB", "ABC", "ABCD", "ABD", "AC", "ACD", "AD", "B", "BC", "BCD", "BD", "C", "CD", "D", ""]

PS

请注意,此解决方案使用递归方法,而您的解决方案使用迭代方法。

PPS

如果您不想在解决方案中出现空字符串"",您可以将其过滤掉:

let myResult = myArray.powerset.map( $0.sort().joinWithSeparator("") ).filter( $0 != "" )

print(myResult) // -> ["A", "AB", "ABC", "ABCD", "ABD", "AC", "ACD", "AD", "B", "BC", "BCD", "BD", "C", "CD", "D"]

【讨论】:

完美!! .这就是我真正想要的 但输出顺序相反,即(而不是 DCBA ,它应该是 ABCD)因为我改变了最后一行 let myResult = array.powerset.map( $0.reverse().joinWithSeparator("/") ).filter( $0 != "" ) 这很有趣,我使用的是IBM Swift 模拟器(swiftlang.ng.bluemix.net),无论我使用sort 还是reverse,结果都是一样的!不管怎样,我很高兴你得到了你的解决方案:) 这个解决方案的复杂性是什么?它碰巧有 38 个项目的项目数量限制,它对它来说太大了【参考方案2】:

您似乎想要拥有数组的Power set。

在数学中,任何集合 S 的幂集(或幂集)是 S 的所有子集,包括空集和 S 本身。

我在GitHub 上找到了此代码。

extension Array 
    var powerset: [[Element]] 
        if count == 0 
            return [self]
        
        else 
            let tail = Array(self[1..<endIndex])
            let head = self[0]

            let withoutHead = tail.powerset
            let withHead = withoutHead.map  $0 + [head] 

            return withHead + withoutHead
        
    


println([1,2,3,4].powerset) -> [[4, 3, 2, 1], [3, 2, 1], [4, 2, 1], [2, 1], [4, 3, 1], [3, 1], [4, 1], [1], [4, 3, 2], [3, 2], [4, 2], [2], [4, 3], [3], [4], []]

【讨论】:

除了 swift 应该是什么? 哦,对不起,是的,它很快,但我可以得到它的解释,因为我无法改变它 尝试运行它并插入一些打印件。这应该能让你很好地理解【参考方案3】:

我知道已经给出了一些很好的答案,但是来自 Java 背景,我只是想放弃一些使用位运算符的见解(令人惊讶的是,它在 Swift 中仍然有效)。

你可以试试这个:

let len = stringArr.count

for i in 0 ..< (1<<len)
    print("", terminator: "")

    for j in 0 ..< len 
        if ((i & (1<<j)) > 0) 
            print(stringArr[j], terminator: "")
        
    

    print("")

您可以找到有关按位运算符here的更多信息

【讨论】:

【参考方案4】:

我找到了一个更简洁的答案。Power set of Collection.

原理是对集合的大小使用归纳,如该链接所示。 这是该链接中的代码副本。并感谢其作者。

extension Collection 
  public var powerSet: [[Element]] 
    guard let fisrt = self.first else return [[]]
    return self.dropFirst().powerSet.flatMap[$0, [fisrt] + $0]
  

let s: Set<Int> = [1,2,3]
s.powerSet //[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]
let a: Array<Int> = [1,2,3]
a.powerSet //[[], [1], [2], [1, 2], [3], [1, 3], [2, 3], [1, 2, 3]]

【讨论】:

【参考方案5】:

我也将使用logic 作为参考拍摄:

extension RangeReplaceableCollection 
    var subSets : [SubSequence] 
        guard !isEmpty else  return [] 
        let count = self.count
        let n = 1 << count - 1
        var subSequences: [SubSequence] = .init(repeating: SubSequence(), count: n-1)
        (0 ..< n).forEach  x in
            autoreleasepool 
                var counter = 0
                for element in self 
                    if x & 1 << counter > 0 
                        subSequences[x-1].append(element)
                    
                    counter += 1
                
            

        
        return subSequences + [self[...]]
    


游乐场测试:

["A", "B", "C","D"].subSets  // [["A"], ["B"], ["A", "B"], ["C"], ["A", "C"], ["B", "C"], ["A", "B", "C"], ["D"], ["A", "D"], ["B", "D"], ["A", "B", "D"], ["C", "D"], ["A", "C", "D"], ["B", "C", "D"], ["A", "B", "C", "D"]]

"ABCD".subSets  // ["A", "B", "AB", "C", "AC", "BC", "ABC", "D", "AD", "BD", "ABD", "CD", "ACD", "BCD", "ABCD"]

【讨论】:

输入数组的最大计数是多少?它似乎在 [SubSequance] 上分配了太大的内存块 @MichałZiobro 检查我的最后一种方法。让我知道这是否解决了内存问题 如果这还不够,我可以在内部循环中添加另一个。 for element in self autoreleasepool 我认为它在这里崩溃并且无法为这个数组分配内存 .init(repeating: SubSequence(), count: n-1) 因为 n 很大 (1 kkkk 子序列太多了。你的意见是什么?

以上是关于快速查找字符串数组的所有组合的主要内容,如果未能解决你的问题,请参考以下文章

获取数组中所有可能的字符组合

在给定的字符串列表中查找字符串的所有字谜

PHP查找数组的所有(有点)唯一组合

使用递归搜索整数数组中元素的所有组合

查找 JavaScript 数组值的所有组合(笛卡尔积)

在数组中查找特定字符串的所有索引的更快方法