How to add filter(_:) method to generic structure in Swift? - swift

I want to add a filter(_:) method to Pyramida structure. It should take a single argument, a closure that: takes an Element and returns a Bool, and return a new Pyramida that contains any elements for which the closure returns true, e.g. values higher than 10.
When I used the same code as per (within exercise) already existent func map also for func filter, its implementation prints out just [false, false, true], however not the values above 10.
Also tried to adjust the func filter as per syntax stated within Developer Documentation, however did not manage it further, too many errors.
struct Pyramida<Element> {
var items = [Element]()
mutating func push(_ newItem: Element) {
items.append(newItem)
}
mutating func pop() -> Element? {
guard !items.isEmpty else {return nil}
return items.removeLast()
}
func map<U>(_ txform: (Element) -> U) -> Pyramida<U> {
var mappedItems = [U]()
for item in items {
mappedItems.append(txform(item))
}
return Pyramida<U>(items: mappedItems)
}
func filter(_ isIncluded: (Element) -> Bool) -> Pyramida<[Int]> {
var filteredItems = [Int]()
for item in items {
if item > 10 {
filteredItems.append(filteredItems(item))
return Pyramida(items: filteredItems)
}
}
}
}
var ints = Pyramida<Int>()
ints.push(2)
ints.push(4)
ints.push(11)
var tripled = ints.map{ 3 * $0 }
print(String(describing: tripled.items))
var aboveTen = ints.filter{ 10 < $0} // code func map<U> for filter<U>
print(String(describing: aboveTen.items))

you have to add this method and if the isIncluded is true you have to append the new element in your array.
func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> Pyramida<Element> {
var newElements: [Element] = []
for number in items where try isIncluded(number) {
newElements.append(number)
}
return Pyramida(items: newElements)
}
and you also can use this.
public func filter(_ isIncluded: (Element) throws -> Bool) rethrows -> Pyramida <Element>{
return Pyramida(items: try items.filter(isIncluded))
}

Related

How to filter an Actor object?

I have an Actor object that I want to be able to iterate and filter.
actor DataModel {
typealias Details = (passed: Bool, scores: [Int])
private(set) var data: [Int: Details] = [:]
func update(_ value: (Bool, [Int]), forKey key: Int) {
data.updateValue(value, forKey: key)
}
subscript(id: Int) -> Details? {
get {
data[id]
}
set {
data[id] = newValue
}
}
func removeAll() {
data.removeAll()
}
}
extension DataModel: AsyncSequence, AsyncIteratorProtocol {
typealias Element = (key: Int, value: Details)
func next() async throws -> Element? {
var iterator = data.makeIterator()
return iterator.next()
}
nonisolated func makeAsyncIterator() -> Data {
self
}
}
let data = DataModel()
await data.update((false, [1, 2]), forKey: 0)
But, whenever I use the filter method, it goes into an infinite loop.
let filtered = data.filter { el in
/// infinite loop
return el.value.passed || el.value.scores.count > 3
}
for try await i in filtered {
print(i)
}
Update
Created a separate iterator, but getting the following error:
Actor-isolated property 'data' can not be referenced from a non-isolated context
extension DataDetail: AsyncSequence {
typealias Element = (key: Int, value: (passed: Bool, scores: [Int]))
typealias AsyncIterator = DataInterator
nonisolated func makeAsyncIterator() -> DataInterator {
return DataInterator(data) /// Actor-isolated property 'data' can not be referenced from a non-isolated context
}
}
struct DataInterator: AsyncIteratorProtocol {
typealias Detail = (key: Int, value: (passed: Bool, scores: [Int]))
private let details: [Int: (passed: Bool, scores: [Int])]
lazy var iterator = details.makeIterator()
init(_ details: [Int: (passed: Bool, scores: [Int])]) {
self.details = details
}
mutating func next() async throws -> Detail? {
let nextDetail = iterator.next()
return nextDetail
}
}
You have a mistake in your next() method. You're creating a new iterator on each call, so every call to your next() method is effectively returning data.first over and over again. It'll never hit nil, so it'll never end.
I'm not sure what the easiest way to fix it is, however. You can't just return data.makeIterator() from makeAsyncIterator(), because data is actor-isolated.
You'll probably want to make a new AsyncIteratorProtocol-conforming struct which wraps your actor and vends the elements of its data in an actor-isolated way

Is it possible to have a same collection instance in a dictionary associated with multiple keys in swift?

I have a Set instance and want to put it into a Dictionary, and associate it with multiple keys so I can lookup/modify it in the future.
Following Python code is what I want to achieve in Swift.
s = set()
D = {}
D["a"] = s
D["b"] = s
D["a"].add("Hello")
D["a"].add("World")
print(D["b"]) # getting {"Hello", "World"} back
I tried something like following in Swift.
var s = Set<String>()
var D = Dictionary<String, Set<String>>()
D["a"] = s // copy of s is assigned
D["b"] = s // another copy of s is assigned
D["a"]!.insert("Hello")
D["a"]!.insert("World")
print(D["b"]!) // empty :(
Since collections in Swift hold value semantics, by the time I put a set into a dictionary, new instance is created. Is there any workaround? I know I could use NSMutableSet instead of Swift's Set, but I want to know how I can approach this by using collections with value semantics if possible.
Ah! Now we get to the heart of it. You just want a reference type based on stdlib rather than using the one that Foundation gives you. That's straightforward to implement, if slightly tedious. Just wrap a Set in a class. If you don't want full SetAlgebra or Collection conformance, you don't have to implement all of these methods. (And you might want some more init methods to make this more convenient, but hopefully those implementations are fairly obvious from your code needs.)
final class RefSet<Element> where Element: Hashable {
private var storage: Set<Element> = Set()
init() {}
}
extension RefSet: Equatable where Element: Equatable {
static func == (lhs: RefSet<Element>, rhs: RefSet<Element>) -> Bool {
return lhs.storage == rhs.storage
}
}
extension RefSet: SetAlgebra {
var isEmpty: Bool { return storage.isEmpty }
func contains(_ member: Element) -> Bool {
return storage.contains(member)
}
func union(_ other: RefSet<Element>) -> RefSet<Element> {
return RefSet(storage.union(other.storage))
}
func intersection(_ other: RefSet<Element>) -> RefSet<Element> {
return RefSet(storage.intersection(other.storage))
}
func symmetricDifference(_ other: RefSet<Element>) -> RefSet<Element> {
return RefSet(storage.symmetricDifference(other.storage))
}
#discardableResult
func insert(_ newMember: Element) -> (inserted: Bool, memberAfterInsert: Element) {
return storage.insert(newMember)
}
#discardableResult
func remove(_ member: Element) -> Element? {
return storage.remove(member)
}
#discardableResult
func update(with newMember: Element) -> Element? {
return storage.update(with: newMember)
}
func formUnion(_ other: RefSet<Element>) {
storage.formUnion(other.storage)
}
func formIntersection(_ other: RefSet<Element>) {
storage.formIntersection(other.storage)
}
func formSymmetricDifference(_ other: RefSet<Element>) {
storage.formSymmetricDifference(other.storage)
}
}
extension RefSet: Collection {
typealias Index = Set<Element>.Index
var startIndex: Index { return storage.startIndex }
var endIndex: Index { return storage.endIndex }
subscript(position: Index) -> Element {
return storage[position]
}
func index(after i: Index) -> Index {
return storage.index(after: i)
}
}

Is there a stable sort that works with partial orders in the standard library? [duplicate]

I've been using the sort() function but it mixes up the relative order.
This is how my code looks.
recipes.sort { $0.skill.value <= $1.skill.value }
Swift API says that:
The sorting algorithm is not stable. A nonstable sort may change the
relative order of elements that compare equal.
How can I change this so that the relative order stays the same as before?
The implementation below just work like the sorted method in the standard library, without additional limit.
extension RandomAccessCollection {
/// return a sorted collection
/// this use a stable sort algorithm
///
/// - Parameter areInIncreasingOrder: return nil when two element are equal
/// - Returns: the sorted collection
public func stableSorted(by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> [Element] {
let sorted = try enumerated().sorted { (one, another) -> Bool in
if try areInIncreasingOrder(one.element, another.element) {
return true
} else {
return one.offset < another.offset
}
}
return sorted.map { $0.element }
}
}
A stable sort needs to preserve the original order. So we give every element a weight of order besides its value, the index, then the original sort method will just work, as there will never be 2 equal elements.
I appreciate the elegance of leavez's answer. I adapted it to have the same signature as Sequence.sorted(by:):
extension Sequence {
func stableSorted(
by areInIncreasingOrder: (Element, Element) throws -> Bool)
rethrows -> [Element]
{
return try enumerated()
.sorted { a, b -> Bool in
try areInIncreasingOrder(a.element, b.element) ||
(a.offset < b.offset && !areInIncreasingOrder(b.element, a.element))
}
.map { $0.element }
}
}
let sortedArray = (recipes as NSArray).sortedArray(options: .stable, usingComparator: { (lhs, rhs) -> ComparisonResult in
let lhs = (lhs as! Recipe)
let rhs = (rhs as! Recipe)
if lhs.skill.value == rhs.skill.value {
return ComparisonResult.orderedSame
} else if lhs.skill.value < rhs.skill.value {
return ComparisonResult.orderedAscending
} else {
return ComparisonResult.orderedDescending
}
})
Took from here: https://medium.com/#cocotutch/a-swift-sorting-problem-e0ebfc4e46d4
In Swift 5 sort() uses stable implementation and soon it will become officially guaranted to be stable.
From Swift forums:
...
On the other hand, the actual implementation calls
/// Sorts the elements of this buffer according to `areInIncreasingOrder`,
/// using a stable, adaptive merge sort.
///
/// The adaptive algorithm used is Timsort, modified to perform a straight
/// merge of the elements using a temporary buffer.
#inlinable
public mutating func _stableSortImpl(
by areInIncreasingOrder: (Element, Element) throws -> Bool
) rethrows { ... }
And
If I recall, sort() is currently stable, but it is not yet guaranteed
to be stable (meaning, the fact that it is stable is currently an
implementation detail, and a future version of Swift could ship an
unstable algorithm instead).
I use this wrapper
extension Array where Element: Comparable, Element: AnyObject {
public func stableSorted() -> [Element] {
let array = self as NSArray
let result = array.sortedArray(options: .stable) { (left, right) -> ComparisonResult in
let left = left as! Element
let right = right as! Element
if left < right {
return ComparisonResult.orderedAscending
}
if left > right {
return ComparisonResult.orderedDescending
}
return ComparisonResult.orderedSame
}
return result as! [Element]
}
public func stableReversed() -> [Element] {
let array = self as NSArray
let result = array.sortedArray(options: .stable) { (left, right) -> ComparisonResult in
let left = left as! Element
let right = right as! Element
if left > right {
return ComparisonResult.orderedAscending
}
if left < right {
return ComparisonResult.orderedDescending
}
return ComparisonResult.orderedSame
}
return result as! [Element]
}
}
I appreciate the elegance of Tom's answer. Harking back to my Perl days I've reworked it to use ComparisonResult and the spaceship (<=>) operator:
extension Sequence {
func sorted(with comparator: (Element, Element) throws -> ComparisonResult) rethrows -> [Element]
{
return try enumerated()
.sorted { (try comparator($0.element, $1.element) || $0.offset <=> $1.offset) == .orderedAscending }
.map { $0.element }
}
}
extension Comparable {
static func <=> (lhs: Self, rhs: Self) -> ComparisonResult {
if lhs < rhs { return .orderedAscending }
if lhs > rhs { return .orderedDescending }
return .orderedSame
}
}
extension ComparisonResult {
static func || (lhs: Self, rhs: #autoclosure () -> Self) -> ComparisonResult {
if lhs == .orderedSame {
return rhs()
}
return lhs
}
}

Adopting CollectionType (Collection) in Swift

I'm writing a graphics library to display data in a graph. Since most of the projects I do tend to have a large learning component in them, I decided to create a generically typed struct to manage my data set DataSet<T: Plottable> (note here that Plottable is also Comparable).
In trying to conform to MutableCollectionType, I've run across an error. I'd like to use the default implementation of sort(), but the compiler is giving the following error when trying to use the sorting function.
Ambiguous reference to member 'sort()'
Here's a code example:
var data = DataSet<Int>(elements: [1,2,3,4])
data.sort() //Ambiguous reference to member 'sort()'
The compiler suggests two candidates, but will not actually display them to me. Note that the compiler error goes away if I explicitly implement sort() on my struct.
But the bigger question remains for me. What am I not seeing that I expect the default implementation to be providing? Or am I running across a bug in Swift 3 (this rarely is the case... usually I have overlooked something).
Here's the balance of the struct:
struct DataSet<T: Plottable>: MutableCollection, BidirectionalCollection {
typealias Element = T
typealias Iterator = DataSetIterator<T>
typealias Index = Int
/**
The list of elements in the data set. Private.
*/
private var elements: [Element] = []
/**
Initalize the data set with an array of data.
*/
init(elements data: [T] = []) {
self.elements = data
}
//MARK: Sequence Protocol
func makeIterator() -> DataSetIterator<T> {
return DataSetIterator(self)
}
//MARK: Collection Protocol
subscript(_ index:DataSet<T>.Index) -> DataSet<T>.Iterator.Element {
set {
elements[index] = newValue
}
get {
return elements[index]
}
}
subscript(_ inRange:Range<DataSet<T>.Index>) -> DataSet<T> {
set {
elements.replaceSubrange(inRange, with: newValue)
}
get {
return DataSet<T>(elements: Array(elements[inRange]))
}
}
//required index for MutableCollection and BidirectionalCollection
var endIndex: Int {
return elements.count
}
var startIndex: Int {
return 0
}
func index(after i: Int) -> Int {
return i+1
}
func index(before i: Int) -> Int {
return i-1
}
mutating func append(_ newElement: T) {
elements.append(newElement)
}
// /**
// Sorts the elements of the DataSet from lowest value to highest value.
// Commented because I'd like to use the default implementation.
// - note: This is equivalent to calling `sort(by: { $0 < $1 })`
// */
// mutating func sort() {
// self.sort(by: { $0 < $1 })
// }
//
// /**
// Sorts the elements of the DataSet by an abritrary block.
// */
// mutating func sort(by areInIncreasingOrder: #noescape (T, T) -> Bool) {
// self.elements = self.elements.sorted(by: areInIncreasingOrder)
// }
/**
Returns a `DataSet<T>` with the elements sorted by a provided block.
This is the default implementation `sort()` modified to return `DataSet<T>` rather than `Array<T>`.
- returns: A sorted `DataSet<T>` by the provided block.
*/
func sorted(by areInIncreasingOrder: #noescape (T, T) -> Bool) -> DataSet<T> {
return DataSet<T>(elements: self.elements.sorted(by: areInIncreasingOrder))
}
func sorted() -> DataSet<T> {
return self.sorted(by: { $0 < $1 })
}
}
Your DataSet is a BidirectionalCollection. The sort() you're trying to use requires a RandomAccessCollection. The most important thing you need to add is an Indicies typealias.
typealias Indices = Array<Element>.Indices
Here's my version of your type:
protocol Plottable: Comparable {}
extension Int: Plottable {}
struct DataSet<Element: Plottable>: MutableCollection, RandomAccessCollection {
private var elements: [Element] = []
typealias Indices = Array<Element>.Indices
init(elements data: [Element] = []) {
self.elements = data
}
var startIndex: Int {
return elements.startIndex
}
var endIndex: Int {
return elements.endIndex
}
func index(after i: Int) -> Int {
return elements.index(after: i)
}
func index(before i: Int) -> Int {
return elements.index(before: i)
}
subscript(position: Int) -> Element {
get {
return elements[position]
}
set {
elements[position] = newValue
}
}
subscript(bounds: Range<Int>) -> DataSet<Element> {
get {
return DataSet(elements: Array(elements[bounds]))
}
set {
elements[bounds] = ArraySlice(newValue.elements)
}
}
}
var data = DataSet(elements: [4,2,3,1])
data.sort()
print(data.elements) // [1,2,3,4]
You don't actually need an Iterator if you don't want one. Swift will give you Sequence automatically if you implement Collection.

What is the Swift equivalent of C#/.NET/LINQ's Enumerable.All method?

I want a function that applies a given function to a sequence and returns true iff the given function returns true for every element of the sequence, like Enumerable.All from the C#/.NET/LINQ world.
Building up on Jon's answer: You can use contains()
instead of an (explicit) loop:
extension SequenceType {
func all(#noescape predicate: (Self.Generator.Element) throws -> Bool)
rethrows -> Bool {
return !(try contains { !(try predicate($0)) })
}
}
There isn't a built-in function to do this, but you can easily add your own as a protocol extension method:
extension SequenceType {
func all(#noescape predicate: (Self.Generator.Element) throws -> Bool)
rethrows -> Bool {
for i in self {
if !(try predicate(i)) { return false }
}
return true
}
}
and then use it on a sequence like:
let allPositive = [1, 2, 3].all { $0 > 0 }
Not sure if this helps, but you can achieve the same outcome using reduce. Here's a quick playground I put together to prove the concept:
let nums = [2, 2, 3, 4]
// Will only evaluate to true if all numbers are even.
let allEven = nums.reduce(true) {
if !$0 || $1 % 2 != 0 {
return false
}
return true
}