I have an Array of String and I want to find all the possible combinations of its element
For Example :
Array = [A,B,C,D]
should produce result as :
[A,AB,AC,AD,ABC,ABD,ACD,ABCD,B,BC,BD,BCD,C,CD,D]
Here is my Logic :
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)
Its Output is :
["A", "AB", "AC", "AD", "ABC", "ABD", "ACD", "B", "BC", "BD", "BBD",
"C", "CD", "D"]
This output is missing ABCD and wrongly printed BCD as BBD
Anyone Please Help me in this by Enhancing my code or suggesting your own logic for this.
#yannick's answer is very close.
By computing a Power Set of your set, you obtain all the possible subsets (including your original set and the empty set).
Once you have obtained the Power Set, all you have to do is join the subsets into a single string in order to obtain the result that you're looking for.
Here's the complete solution (along with updated code and plenty of comments):
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
Note that this solution uses a recursive approach, while yours was using an iterative approach.
PPS
If you don't want the empty string "" in your solution, you can just filter it away:
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"]
It looks like you want to have the Power set of your array.
In mathematics, the power set (or powerset) of any set S is the set of
all subsets of S, including the empty set and S itself.
I found this Code on 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], []]
I find a neater answer for it.Power set of Collection.
The principle is using induction on the size of a collection, as showed on that link.
Here is the copy of code from that link. And all credits to its author.
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]]
I know some good answers have been given already, but coming from a Java background, I just wanted to drop some insights using bitwise operators (which surprisingly still work in Swift).
You can try this out:
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("}")
}
You can find more information on bitwise operators here
I will take a shot also using this logic as reference:
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[...]]
}
}
Playground Testing:
["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"]
Related
Let's say we have an array:
var scrambledAlphabet = ["B", "C", "D", "E", "H", "F", "G", "A"]
and we want sort it by moving two items: item 7 ("A") to location 0, and item 4 ("H") to 7, described with an array of tuples:
var moves = [(7, 0), (4, 7)]
So, the desired result is:
["A", "B", "C", "D", "E", "F", "G", "H"]
Spontaneous that would be easy solved with this:
var scrambledAlphabet = ["B", "C", "D", "E", "H", "F", "G", "A"]
var moves = [(7, 0), (4, 7)]
for (i, j) in moves {
scrambledAlphabet.insert(scrambledAlphabet.remove(at: i), at: j)
}
print(scrambledAlphabet)
But it doesn't work. The output is:
["A", "B", "C", "D", "H", "F", "G", "E"]
The problem is that once the first item is moved, the index of the next item is altered. So, what would be the best way to tackle this? I find this surprisingly hard to crack. Any help is appreciated.
The restriction is that the two variables, scrambledAlphabet and moves, must be able to grow to any number.
And also one important note, the move-to-index (second number in the tuple) is referring to the old array, not the newly created. So, the inputs ["B", "C", "E", "D", "H", "F", "G", "A"] and [(7, 0), (4, 7), (3, 2)] should result in:
["A", "B", "C", "D", "E", "F", "G", "H"]
Sorry about the confusion about this last bit.
I thought of this (IMO a little clumsy) solution:
var newArray = Array(repeating: "", count: scrambledLetters.count)
for (start, end) in moves {
newArray[end] = scrambledLetters[start]
scrambledLetters[start] = ""
}
var scrambledLetterIndex = -1
func setScrambledLetterIndexToNextNonEmptyString() {
scrambledLetterIndex += 1
while scrambledLetterIndex < scrambledLetters.count - 1 && scrambledLetters[scrambledLetterIndex].isEmpty {
scrambledLetterIndex += 1
}
}
for i in newArray.indices {
if newArray[i] == "" {
setScrambledLetterIndexToNextNonEmptyString()
newArray[i] = scrambledLetters[scrambledLetterIndex]
}
}
scrambledLetters = newArray
Essentially, I first created a new array, and "took out" the strings that needs to be moved, and placed them in the correct position in the new array. That's what the first for loop did.
After the first for loop, the two arrays will look like this:
scrambledLetters: ["B", "C", "D", "E", "", "F", "G", ""]
newArray: ["A", "", "", "", "", "", "" , "H"]
Then, I slowly copied each non-empty item in the scrambled letters array into the new array's empty places.
Because this solution makes use of the empty string, it won't work if the input domain contained empty strings. If that's the case, you'd have to use something like a [String?].
A possible approach is to use an array of all indices which are not the source of any move. Then we can fill the destination sequentially, either from one of the moves, or from one of the “other indices”:
func scramble<T>(array: [T], moves: [(Int, Int)]) -> [T] {
// Moves sorted by increasing destination index:
var moves = moves.sorted(by: { $0.1 < $1.1 })
// All indices which are not the source of a move:
let sourceIndices = Set(moves.map { $0.0 })
var otherIndices = array.indices.filter { !sourceIndices.contains($0)}
// Fill each position with an element of a move source,
// or one of the "other" array elements:
return array.indices.map {
if let (from, to) = moves.first, $0 == to {
moves.removeFirst()
return array[from]
} else {
return array[otherIndices.removeFirst()]
}
}
}
Example 1:
print(scramble(array: ["B", "C", "D", "E", "H", "F", "G", "A"],
moves: [(7, 0), (4, 7)]))
// ["A", "B", "C", "D", "E", "F", "G", "H"]
Example 2:
print(scramble(array: [0, 1, 2, 3, 4, 5, 6, 7],
moves: [(1, 6), (7, 2), (3, 5), (5, 3), (4, 7)]))
// [0, 2, 7, 5, 6, 3, 1, 4]
I solved it by couple the items in the array with their original index, and sorted the moves so that the inserts doesn't scramble the order. Also moved all code into an array extension:
extension Array where Element : Equatable {
mutating func moveItem(from fromIndex: Int, to toIndex: Int) {
self.insert(self.remove(at: fromIndex), at: toIndex)
}
func performIteratedMoves(_ moves: [(Int, Int)]) -> [Element] {
var array = self
let enumeratedArray = array.enumerated().map{ (index: $0, item: $1) }
let sortedMoves = moves.sorted { $0.1 > $1.1 }
for (i, j) in sortedMoves {
guard let (_, item) = enumeratedArray.first(where:{ $0.index == i }), let correctIndex = array.firstIndex(where:{ $0 == item }) else { continue }
array.moveItem(from: correctIndex, to: j)
}
return array
}
}
Usage:
var scrambledAlphabet = ["B", "C", "E", "D", "H", "F", "G", "A"]
var moves = [(7, 0), (4, 7), (3, 2)]
print(scrambledAlphabet.performIteratedMoves(moves))
// ["A", "B", "C", "D", "E", "F", "G", "H"]
By "upgrouped" I mean elements that are uniq to its left and its right elements.
Example:
arr = ["a", "a", "a", "b", "a", "c", "c", "d", "b"]
We can group arr like this [["a", 3], ["b, 1], ["a", 1], ["c", 2], ["d", 1], ["b", 1]]. Let's say once a letter is "grouped" we are not going to pick any other ungrouped instances of that letter.
So our final answer would be arr = ["b", "d"]
What could be a great option to replace the "regex" part in arr.select{|chr| chr(/\regex/)} (if there is no other ways)?
Edit: added "b" in the end of array. arr.count("b") == 2, but since "b" is ungrouped, it is still part of the return array.
You could do it in two steps without regex:
banned = arr.chunk(&:itself).select { |e| e.last.size > 1 }.map(&:first)
#=> ["a", "c"]
arr.uniq - banned
#=> ["b", "d"]
Basically first we get the list of elements that are grouped and need to be rejected, and then remove those elements from original array.
Here is a step by step example (for banned list):
arr.chunk(&:itself).to_a #=> [["a", ["a", "a", "a"]], ["b", ["b"]], ["a", ["a"]], ["c", ["c", "c"]], ["d", ["d"]], ["b", ["b"]]]
.select { |e| e.last.size > 1 } #=> [["a", ["a", "a", "a"]], ["c", ["c", "c"]]]
.map(&:first) #=> ["a", "c"]
Notice that to_a is added only to show the content of the Enumerable that results from chunk, but it is not used in the final solution since map can be executed on any Enumerable object.
Another option to get banned list could be using each_with_object:
arr.chunk(&:itself).each_with_object([]) { |elem, result| result << elem[0] if elem[1].size > 1 }
#=> ["a", "c"]
This will only iterate arr twice (first option will iterate it 3 times).
I don't know how I'd use a regular expression for this problem, but the method Enumerable#each_cons can be used to advantage.
Let grouped and ungrouped respectively be arrays of elements of a given array arr, where grouped are the grouped elements and ungrouped are the ungrouped elements. Every element is grouped or ungrouped.
My understanding of the question is that we wish to construct an array
(ungrouped - grouped).uniq
where Array#- is array difference.
It is clear that, for i=1,..., arr.size-2, arr[i] is ungrouped if arr[i-1] != arr[i] && arr[i] != arr[i+1]. It's not evident, however, how one determines whether the first and last elements of an array are ungrouped. The definition states that, to be ungrouped, the element must differ from both of it's adjacent elements. Since the first and last elements only have one adjacent element, it follows that the first and last elements are never ungrouped.
The alternative interpretation is that an element is ungrouped if it differs from all of its adjacent elements (that being one for the first and last and two for all others). I will consider these two interpretations separately. For both,
arr = [["a", 3], ["b", 1], ["a", 1], ["c", 2], ["d", 1], "b"]
Ungrouped elements must differ from both of their adjacent elements
ungrouped, grouped = [arr.first, *arr, arr.last].each_cons(3).
with_object([[],[]]) do |(p,c,n), (ungrouped, grouped)|
(c==p || c==n ? grouped : ungrouped) << c
end
(ungrouped - grouped).uniq
# => ["d"]
Ungrouped elements must differ from all of their adjacent elements
ungrouped, grouped = [nil, *arr, nil].each_cons(3).
with_object([[],[]]) do |(p,c,n), (ungrouped, grouped)|
(c==p || c==n ? grouped : ungrouped) << c
end
(ungrouped - grouped).uniq
# => ["b", "d"]
This assumes that no elements of arr equal nil.
The steps for this second interpretation are as follows.
a = [nil, *arr, nil]
#=> [nil, "a", "a", "a", "b", "a", "c", "c", "d", "b", nil]
b = a.each_cons(3)
#=> #<Enumerator: [nil, "a", "a",..., "d", "b", nil]:each_cons(3)>
We can see the elements that will be generated by this enumerator by converting it to an array.
b.to_a
#=> [[nil, "a", "a"], ["a", "a", "a"], ["a", "a", "b"], ["a", "b", "a"],
# ["b", "a", "c"], ["a", "c", "c"], ["c", "c", "d"], ["c", "d", "b"],
# ["d", "b", nil]]
Continuing,
d = b.with_object([[],[]])
#=> #<Enumerator: #<Enumerator: [nil, "a", "a",..., "d", "b", nil]:
# each_cons(3)>:with_object([[], []])>
d.to_a
#=> [[[nil, "a", "a"], [[], []]], [["a", "a", "a"], [[], []]],
# [["a", "a", "b"], [[], []]], [["a", "b", "a"], [[], []]],
# [["b", "a", "c"], [[], []]], [["a", "c", "c"], [[], []]],
# [["c", "c", "d"], [[], []]], [["c", "d", "b"], [[], []]],
# [["d", "b", nil], [[], []]]]
If one examines the return value for the construction of this enumerator, you can see it can be thought of as a compound enumerator.
ungrouped, grouped = d.each do |(p,c,n), (ungrouped, grouped)|
(c==p || c==n ? grouped : ungrouped) << c
end
#=> [["b", "a", "d", "b"], ["a", "a", "a", "c", "c"]]
ungrouped
#=> ["b", "a", "d", "b"]
grouped
#=> ["a", "a", "a", "c", "c"]]
e = ungrouped - grouped
#=> ["b", "d", "b"]
e.uniq
#=> ["b", "d"]
Let's take a closer look at the calculation of ungrouped and grouped. The first element of the enumerator d is passed to the block and the block variables are assigned values.
(p,c,n), (ungrouped, grouped) = d.next
#=> [[nil, "a", "a"], [["b", "a", "d", "b"], ["a", "a", "a", "c", "c"]]]
p
#=> nil
c
#=> "a"
n
#=> "a"
ungrouped
#=> []
grouped
#=> []
c==p || c==n
#=> "a"==nil || "a"=="a"
#=> true
Therefore,
grouped << c
#=> ["a"]
The remaining calculations are similar, as are the calculations under the first assumption concerning the first and last elements of the array.
Let's say I have an array of strings:
var array: [String] = ["a", "a", "b", "c", "c", "c", "d", "d"]
In the array, I have 4 times a, 1 time b, 3 times c and 2 times d.
I want to update the a value from 4 to 7, and the c value from 3 to 1.
The maximum times I want a single string to be in the array is up to 10 times.
I tried to do it using this:
for _ in 0..<10 {
if array.contains("a") {
if let index = array.index(of: "a") {
array.remove(at: index)
}
}
}
for _ in 0..<7 {
array += ["a"]
}
First, in a loop which runs 10 times, I check every time if the array still contains a, and if so then I remove it. After that, I run a loop for 7 times, and this loop adds every time another a value to the array, until there are supposed to be 7 a in the array.
This isn't what's really happening. What really happening is that it replaces all objects in the array to a, and definitely runs more than 7 times.
What can I do to solve it?
I would suggest using a dictionary. This current method is not really efficient.
var dict = [
"a": 4,
"b": 8
]
This way you can update the value for each letter without having to repeat them in an array. To set a dictionary value you can use the subscript:
dict["a"] = 2
This seems more suited to what you're trying to do.
If you want to bring the occurrences of a given element to n you can write something like this.
extension Array where Element == String {
func updated(numOccurrencies: Int, ofWord word: String) -> [String] {
let currentOccurrencies = self.filter { $0 == word }.count
let delta = numOccurrencies - currentOccurrencies
if delta > 0 {
let newOccurrencies = Array<String>(repeatElement(word, count: delta))
return self + newOccurrencies
}
if delta < 0 {
var numElmsToDelete = -delta
return filter {
guard $0 == word else { return true }
guard numElmsToDelete > 0 else { return true }
numElmsToDelete -= 1
return false
}
}
return self
}
}
Examples
Now given you array
let words = ["a", "a", "b", "c", "c", "c", "d", "d"]
You can produce a new array bringing the occurrences of "a" to different values
words.updated(numOccurrencies: 0, ofWord: "a")
// ["b", "c", "c", "c", "d", "d"]
words.updated(numOccurrencies: 1, ofWord: "a")
// ["a", "b", "c", "c", "c", "d", "d"]
words.updated(numOccurrencies: 2, ofWord: "a")
// ["a", "a", "b", "c", "c", "c", "d", "d"]
words.updated(numOccurrencies: 3, ofWord: "a")
// ["a", "a", "b", "c", "c", "c", "d", "d", "a"]
words.updated(numOccurrencies: 4, ofWord: "a")
// ["a", "a", "b", "c", "c", "c", "d", "d", "a", "a"]
Sorting
As you can see the new occurrences of "a" ad added at the end of the array. If you want the array to stay sorted just append .sorted() to each invocation
words.updated(numOccurrencies: 4, ofWord: "a").sorted()
// ["a", "a", "a", "a", "b", "c", "c", "c", "d", "d"]
"The maximum times I want a single string to be in the array is up to 10 times"
I am now assuming the output array must be sorted.
I am going to use a different approach for this. I will calculate for each word, the number of occurrences we expect for that word in the output array.
Each occurrences will be the minimum between 10 and the current occurrences for that word.
Example
a: min(10, 2) = 2
b: min(10, 1) = 1
...
Once I have the number of occurrences expected for each word I can build the final sorted array from scratch.
extension Array where Element == String {
func updated(withMaximumOccurrencies max: Int) -> [String] {
let countedSet = NSCountedSet(array: self)
let uniqueWords = Set(self)
return uniqueWords
.reduce([String]()) { (res, word) -> [String] in
let occurrencies = Swift.min(max, countedSet.count(for: word))
return res + [String](repeatElement(word, count: occurrencies))
}.sorted()
}
}
Examples
let words: [String] = ["a", "a", "b", "c", "c", "c", "d", "d"]
words.updated(withMaximumOccurrencies: 1)
["a", "b", "c", "d"]
words.updated(withMaximumOccurrencies: 2)
["a", "a", "b", "c", "c", "d", "d"]
words.updated(withMaximumOccurrencies: 10)
["a", "a", "b", "c", "c", "c", "d", "d"]
I have:
stuff = [1, 2, "a", "b", "c", "d", 4, 5, "z", "l", "m", "l", 5, 4, 4, 77]
Numbers come in groups of multiples of two, and letters come in groups of multiples of four.
I want to group numbers in twos and letters in fours like this:
stuff_processed = [
[1, 2],
["a", "b", "c", "d"],
[4, 5],
["z", "l", "m", "l"],
[5, 4],
[4, 77]
]
The order inside of an array that holds numbers or letters is important, the order between the arrays I do not care about.
I know stuff.each_slice(2).to_a will take me part of the way. I can't figure out how to get all the way to what I need though.
stuff
.chunk(&:class)
.flat_map{|klass, a| a.each_slice(klass == Fixnum ? 2 : 4).to_a}
# => [[1, 2], ["a", "b", "c", "d"], [4, 5], ["z", "l", "m", "l"], [5, 4], [4, 77]]
arr = [1, 2, "a", "b", "c", "d", 4, 5, "z", "l", "m", "l", "s", "t",
"u", "v", 5, 4, 4, 77, 91, 65]
H = { Fixnum=>1, String=>3 }
count = 0
arr.slice_when do |a,b|
if a.class == b.class && count < H[a.class]
count += 1
false
else
count = 0
true
end
end.to_a
# => [[1, 2], ["a", "b", "c", "d"], [4, 5], ["z", "l", "m", "l"],
# ["s", "t", "u", "v"], [5, 4], [4, 77], [91, 65]]
See Enumerable#slice_when, which first appeared in Ruby v2.2.
This Array#conditional_slice method accepts a Block and returns an Enumerator :
stuff = [1, 2, "a", "b", "c", "d", 4, 5, "z", "l", "m", "l", 5, 4, 4, 77]
class Array
def conditional_slice(&block)
clone = self.dup
Enumerator.new do |yielder|
until clone.empty? do
yielder << clone.shift(block_given? ? block.call(clone.first) : 1)
end
end
end
end
sliced_stuff = stuff.conditional_slice{|x| x.is_a?(Numeric) ? 2 : 4}
puts sliced_stuff.to_a.inspect
# => [[1, 2], ["a", "b", "c", "d"], [4, 5], ["z", "l", "m", "l"], [5, 4], [4, 77]]
I am wondering is there any build-in function I can sort a array according to another array. For example: sort testStringArray according to testIntArray
var testStringArray = ["a", "b", "c", "d", "e"]
var testIntArray = [21, 3, 43, 5, 1]
After the function, testStringArray will be
testIntArray.sort // [1, 3, 5, 21, 43]
testStringArray // ["e", "b", "d", "a", "c"]
var array1 = ["a", "b", "c", "d", "e"]
var array2 = [21, 3, 43, 5, 1]
let sorted = zip(array1, array2).sort { $0.1 < $1.1 }
array1 = sorted.map { $0.0 }
array2 = sorted.map { $0.1 }
print(array1) // ["e", "b", "d", "a", "c"]
print(array2) // [1, 3, 5, 21, 43]
Something like this? I feel like it can be done better...
EDIT:
This doesn't feel like it's much better...
zip(array1, array2).sort { $0.1 < $1.1 }.forEach {
array1.removeAtIndex(array1.indexOf($0.0)!)
array1.insert($0.0, atIndex: array1.count)
array2.removeAtIndex(array2.indexOf($0.1)!)
array2.insert($0.1, atIndex: array2.count)
}
print(array1) // ["e", "b", "d", "a", "c"]
print(array2) // [1, 3, 5, 21, 43]