Last active
March 14, 2019 17:38
-
-
Save jpmcglone/28a1a0083c15fc72a188 to your computer and use it in GitHub Desktop.
array.filter into multiple arrays in one pass
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public struct ConditionalArrayFilter <Element> { | |
let condition: (Element) -> Bool // the condition to meet | |
private var _array = Array<Element>() | |
var array: Array<Element> { | |
get { return _array } | |
} | |
init(condition: (Element) -> Bool) { self.condition = condition } | |
} | |
private extension ConditionalArrayFilter { | |
mutating func append(element: Element) { | |
if condition(element) { | |
_array.append(element) | |
} | |
} | |
} | |
extension Array { | |
func filter(filters:[ConditionalArrayFilter<Element>]) { | |
for element in self { | |
for var filter in filters { | |
filter.append(element) | |
} | |
} | |
} | |
} | |
/****************************/ | |
/** Demo of the above code **/ | |
/****************************/ | |
class ConditionalArrayLoaderTest { | |
func test() { | |
// What's great is this is done in O(n) | |
let even = ConditionalArrayFilter<Int> { int in | |
return int % 2 == 0 | |
} | |
let odd = ConditionalArrayFilter<Int> { int in | |
return int % 2 == 1 | |
} | |
let by5 = ConditionalArrayFilter<Int> { int in | |
return int % 5 == 0 | |
} | |
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] | |
numbers.filter([even, odd, by5]) | |
print(even.array) | |
print(odd.array) | |
print(by5.array) | |
} | |
} |
It seems if the ratio c:i is large, the savings shrink and are maybe ignorable. But hey, this is just as easy to use as .filter 3 times, so any savings is better to me :)
Another bonus is, if you hold on to the ConditionalArrayFilter object, you can use the .condition closure to test another Element (of the same type) against it.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Some math :D
Let n = size of array
Let k = number of conditions
Let i = number of cycles per iteration of array
Let c = number of cycles per condition check
Old way, using 3 .filters for 3 arrays, passing 3 times
k_(n_(c + i))
= k*(nc + in)
= knc + kin
= ckn + ikn
This way, using 1 .filter for 3 arrays, passing 1 time
n*(kc + i)
= nkc + ni
= ckn + in
Ratio
(ckn + ikn) / (ckn + in)
= (ck + ik) / (ck + i)
= k ((c + i) / (ck + i))
The old way is
k ((c + i) / (ck + i)) more cycles than the new way.
case 1:
n = 10,000
k = 5
i = 1 (assuming 1 cpu cycle. unlikely, but conservative)
c = 1 (assuming 1 cpu cycle. unlikely, but conservative)
old way:
1 * 5 * 10,000 + 1 * 5 * 10, 000
= 100,000
new way:
1 * 5 * 10,000 + 1 * 10,000
= 60,000
This is a significant improvement.
40% more efficient in this case.
case 2:
n = 1,000
k = 2
i = 2 (assuming i is 2 * c)
c = 1 (assuming 1 cpu cycle. unlikely, but conservative)
old way:
1 * 2 * 1,000 + 2 * 2 * 1,000 = 6,000
new way:
1 * 2 * 1,000 + 2 * 1,000 = 4,000
This is a significant improvement.
33% more efficient in this case.