Swift method on generic 2 dimensional Array - swift

I would like to create an extension method on the Array type when the array is a 2 dimensional array, ex. [[Int]], but the type should be generic. I'm trying to do something like this:
extension Array [where Element : ???] {
public func transposed() -> ??? {
// ...
}
}

This worked in Swift 4.
extension Array where Element: Collection {
public func transposed() -> [[Element.Iterator.Element]] {
var result : [[Element.Iterator.Element]] = [[]]
for row in self {
for (y,column) in row.enumerated() {
while (result.count <= y) {
result.append([])
}
result[y].append(column)
}
}
return result
}
}
Then also unit testing passed:
func testTransposed() {
XCTAssertEqual([[1]].transposed(), [[1]])
XCTAssertEqual([[1,2,3],[4,5]].transposed(), [[1,4],[2,5],[3]])
XCTAssertEqual([[4,1],[5,2],[3]].transposed(),[[4,5,3],[1,2]])
XCTAssertEqual([[1,2,3]].transposed(), [[1],[2],[3]])
XCTAssertEqual([[1],[2],[3]].transposed(),[[1,2,3]])
}

You could do this:
extension Array
{
func transposed<T>() -> [[T]] where Element == Array<T>
{
return self[0].indices.map{ i in self.map{$0[i]} }
}
}
let a = [ [1,2,3],
[4,5,6],
[7,8,9] ]
for r in a.transposed() {print(r)}
// [1, 4, 7]
// [2, 5, 8]
// [3, 6, 9]
// note that the matrix cannot be sparse

Related

Swift how to make a set with multiplicity (multiset)

I am substracting two Array of Integers. I did the substraction using sets :
let numbersA = [1, 2, 3]
let numbersB = [3, 4, 5]
Set(numbersA).subtracting(numbersB)
but I then realized that I have multiplicity in my arrays, and I should take it into account. What is the data structure for multisets in Swift?
In swift 5, there is no Multiset implementation in the core library.
You can reproduce the Multiset behavior by using a dictionary [Element:Multiplicity].
Your code will be:
let numbersA = [1, 2, 3, 3]
let numbersB = [3, 4, 5]
Set(numbersA).subtracting(numbersB) // [1, 2, 3]
As pointed out by Leo Dabus in comment, this gives you an unordered collection as a result.
You can find a good tutorial on multisets at https://github.com/raywenderlich/swift-algorithm-club/tree/master/Multiset
Here is a ready to use implementation of multiset. I added to it the substracting implementation. Notice it can be considered an incomplet implementation of a Multiset since, for exemple, it doesn't extends the Collection protocol.
//
// Multiset.swift
// Multiset
//
// Created by Simon Whitaker on 28/08/2017.
//
// Extended by Jeremy Cochoy on 17/11/2019
import Foundation
public struct Multiset<T: Hashable> {
private var storage: [T: UInt] = [:]
public private(set) var count: UInt = 0
public init() {}
public init<C: Collection>(_ collection: C) where C.Element == T {
for element in collection {
self.add(element)
}
}
public mutating func add (_ elem: T) {
storage[elem, default: 0] += 1
count += 1
}
public mutating func remove (_ elem: T) {
if let currentCount = storage[elem] {
if currentCount > 1 {
storage[elem] = currentCount - 1
} else {
storage.removeValue(forKey: elem)
}
count -= 1
}
}
public func isSubSet (of superset: Multiset<T>) -> Bool {
for (key, count) in storage {
let supersetcount = superset.storage[key] ?? 0
if count > supersetcount {
return false
}
}
return true
}
public func count(for key: T) -> UInt {
return storage[key] ?? 0
}
public var allItems: [T] {
var result = [T]()
for (key, count) in storage {
for _ in 0 ..< count {
result.append(key)
}
}
return result
}
public func subtracting(_ elems: [T]) -> Multiset<T> {
var resultSet = self
elems.forEach { resultSet.remove($0) }
return resultSet
}
}
// MARK: - Equatable
extension Multiset: Equatable {
public static func == (lhs: Multiset<T>, rhs: Multiset<T>) -> Bool {
if lhs.storage.count != rhs.storage.count {
return false
}
for (lkey, lcount) in lhs.storage {
let rcount = rhs.storage[lkey] ?? 0
if lcount != rcount {
return false
}
}
return true
}
}
// MARK: - ExpressibleByArrayLiteral
extension Multiset: ExpressibleByArrayLiteral {
public init(arrayLiteral elements: T...) {
self.init(elements)
}
}
As you say, swift does not have Multiset as a native type.
I implemented a fairly thorough implementation of Multiset in Swift here:
https://github.com/Cortado-J/Multiset
and full documentation of that library with usage examples here:
https://cortado-j.github.io/Multiset/Structs/Multiset.html

Highest frequency element in the dictionary

I am trying to find the highest frequency element in the given as follows.
First, I am trying to build a dictionary and count the each element based on frequency.
I am stuck how to extract max value from the constructed dictionary.
Input: [3,2,3]
Output: 3
func majorityElement(_ nums1: [Int]) -> Int {
var num1Dict = Dictionary(nums1.map{ ($0, 1) }, uniquingKeysWith : +)
return num1Dict.values.max() // ????
}
You have correctly constructed num1Dict, which will be something like this for the input [3,2,3]:
[2:1, 3:2]
values.max() will return 2, because out of all the values in the dictionary (1 and 2), 2 is the highest.
See your error now?
You need to return the key associated with the highest value, not the highest value.
One very straightforward way is to do this:
func majorityElement(_ nums1: [Int]) -> Int? { // you should probably return an optional here in case nums1 is empty
let num1Dict = Dictionary(nums1.map{ ($0, 1) }, uniquingKeysWith : +)
var currentHigh = Int.min
var mostOccurence: Int?
for kvp in num1Dict {
if kvp.value > currentHigh {
mostOccurence = kvp.key
currentHigh = kvp.value
}
}
return mostOccurence
}
You can use reduce(into:) to generate a Dictionary with the elements and their frequencies, then sort your array using those frequencies, then simply return the last element (based on ascending ordering) of the sorted array.
extension Array where Element: Comparable & Hashable {
func sortByNumberOfOccurences() -> [Element] {
let occurencesDict = self.reduce(into: [Element:Int](), { currentResult, element in
currentResult[element, default: 0] += 1
})
return self.sorted(by: { current, next in occurencesDict[current]! < occurencesDict[next]!})
}
func elementWithHighestFrequency() -> Element? {
return sortByNumberOfOccurences().last
}
}
Disclaimer: the sortByNumberOfOccurences method is copied from another answer of mine.
The mathematical name for what you're looking for (the most frequent element in a collection) is called the mode. There could be ties (e.g. [1, 1, 2, 2, 3, 3] has 3 modes: [1, 2, 3])
If you want any one of the modes (not caring which ones, specifically), you can use Dictionary.max(by:), which you can use to find the (element, count) pair with the highest count (which is the dict value). Then, you can get the key of this pair, which will be the mode element.
extension Sequence where Element: Hashable {
func countOccurrences() -> [Element: Int] {
return self.reduce(into: [:]) { (occurences, element) in occurences[element, default: 0] += 1}
}
func mode() -> Element? {
return self.countOccurrences()
.max(by: { $0.value < $1.value })?
.key
}
func modes() -> [Element] {
var firstModeNumOccurences: Int? = nil
let modes = countOccurrences()
.sorted { pairA, pairB in pairA.value > pairB.value } // sorting in descending order of num occurences
.lazy
.prefix(while:) { (_, numOccurences) in
if firstModeNumOccurences == nil { firstModeNumOccurences = numOccurences }
return numOccurences == firstModeNumOccurences
}
.map { (element, _) in element }
return Array(modes)
}
}
print([1, 2, 3, 3, 4, 4].mode() as Any) // => 3 or 4, non-deterministic
print([1, 2, 3, 3, 4, 4].modes() as Any) // => [3, 4]

Does Swift have a function similar to numpy.diff that calculates the difference between adjacent elements of an array

I'm trying to convert some Python code to Swift and wondering if there is an existing function to calculate the difference between successive elements in a Swift array. For example:
diff([1,3,5,6,10]) would return [2,2,1,4]
No, but it could be very easily implemented:
let a = [1, 3, 5, 6, 10]
zip(a.dropFirst(), a).map(-) // => [2, 2, 1, 4]
It's simple enough that it's probably not worth wrapping into a function, but if you insist:
extension Collection where Element: Numeric {
func diff() -> [Element] {
return zip(self.dropFirst(), self).map(-)
}
}
[1, 3, 5, 6, 10].diff() // => [2, 2, 1, 4]
If you need the result to be lazily evaluated, you can do this:
extension Collection where Element: Numeric {
func diff() -> AnyCollection<Element> {
return AnyCollection(zip(self.dropFirst(), self).lazy.map(-))
}
}
You can use reduce(into:) combined with dropfirst to achieve what you want:
extension Collection where Element: SignedNumeric {
func diff() -> [Element] {
guard var last = first else { return [] }
return dropFirst().reduce(into: []) {
$0.append($1 - last)
last = $1
}
}
}
Another option is to use map and defer:
extension Collection where Element: SignedNumeric {
func diff() -> [Element] {
guard var last = first else { return [] }
return dropFirst().map { element in
defer { last = element }
return element - last
}
}
}
let arr = [1,3,5,6,10]
print(arr.diff()) // "[2, 2, 1, 4]\n"
There's no built in function for this, but you can easily implement it recursively. Thanks for the HeadTail extension for #Alexander.
extension Array {
func headTail<ReturnType>(_ closure: (Element?, [Element]) -> ReturnType) -> ReturnType {
return closure(self.first, Array(self.dropFirst()))
}
}
extension Array where Element == Int {
func diff() -> [Int] {
return self.headTail { head, tail in
guard let head = head, let next = tail.first else { return [] } //base case, empty list
return [next - head] + tail.diff()
}
}
}

Extension on a collection type in Swift to find all the objects after an object

I'd like to write an extension on CollectionType in Swift that will find the x objects after an object in an array. Obviously it needs be protected to work even if there are no objects after the item.
In my head the signatures something like this:
func itemsAfterItem(item: T, limit: Int?) -> [T]
I can't figure out how to implement it though, could someone help?
A possible implementation for arbitrary collections of
Equatable elements (explanations inline). The main
challenge is to get the parameter types and constraints right.
extension CollectionType where Generator.Element: Equatable,
SubSequence.Generator.Element == Generator.Element {
func itemsAfterItem(item: Generator.Element, limit: Index.Distance?) -> [Generator.Element] {
if let idx = indexOf(item) where idx != endIndex {
// Start after the given item:
let from = idx.advancedBy(1)
// Up to min(from + limit, endIndex):
let to = limit.map { from.advancedBy($0, limit: endIndex) } ?? endIndex
// Return slice as an array:
return Array(self[from..<to])
} else {
// Item not found, or only at the last position.
return []
}
}
}
Understanding the
let to = limit.map { from.advancedBy($0, limit: endIndex) } ?? endIndex
part is left as an exercise to the reader :)
Examples:
[1, 2, 3, 4, 5, 6].itemsAfterItem(2, limit: 2) // [3, 4]
["x", "y", "z"].itemsAfterItem("y", limit: 4) // ["z"]
[1, 2, 3].itemsAfterItem(7, limit: 4) // []
[1.1, 2.2, 3.3].itemsAfterItem(1.1, limit: nil) // [2.2, 3.3]
Example for a non-array collection:
"abcdef".characters.itemsAfterItem("b", limit: 2) // ["c", "d"]
Just because I liked the challenge ;)
extension Array where Element : Equatable {
func itemsAfterItem(item: Element, limit: Int? = nil) -> [Element] {
if let from = self.indexOf(item) where from < self.count - 1 {
if let limit = limit where from + limit < self.count {
return Array(self[from+1...from + limit])
}
return Array(self[from+1...self.count-1])
} else {
return []
}
}
}
For the input
let arr = [1, 2, 4, 6, 9]
It results in
arr.itemsAfterItem(2) // [4, 6, 9]
arr.itemsAfterItem(2, limit: 2) // [4, 6]
arr.itemsAfterItem(2, limit: 100) // [4, 6, 9]
arr.itemsAfterItem(9, limit: 2) // []
arr.itemsAfterItem(3, limit: 100) // []
I think you can try this:
func itemsAfterItem(item: T, limit: Int?) -> [T] {
var counter: Int = 0
var isAfter: Bool = false
let array = [T]()
let newLimit = limit != nil ? limit : myArray.count
for tmpItem in myArray {
if tmpItem == T {
isAfter = true
}
if isAfter && counter < limit {
array.append(tmpItem)
counter += 1
}
}
}
This function will put your T item at the start of the array.
I've not test this function

Xcode Swift: extension of array: "can't invoke.. with argument list .. " [duplicate]

I am trying to write a simple Array extension that provides a 'distinct' method. Here is what I have so far:
extension Array {
func distinct() -> T[] {
var rtn = T[]()
for x in self {
var containsItem = contains(rtn, x)
if !containsItem {
rtn.append(x)
}
}
return rtn
}
}
The problem is that the 'contains' statement fails as follows:
Could not find an overload for 'contains' that accepts the supplied arguments
I am pretty sure the type constraints are correct. Any ideas?
Swift 1.x
The elements in an array don't have to be Equatable, i.e. they don't have be comparable with ==.
That means you can't write that function for all possible Arrays. And Swift doesn't allow you to extend just a subset of Arrays.
That means you should write it as a separate function (and that's probably why contains isn't a method, either).
let array = ["a", "b", "c", "a"]
func distinct<T: Equatable>(array: [T]) -> [T] {
var rtn = [T]()
for x in array {
var containsItem = contains(rtn, x)
if !containsItem {
rtn.append(x)
}
}
return rtn
}
distinct(array) // ["a", "b", "c"]
Update for Swift 2/Xcode 7 (Beta)
Swift 2 supports restricting extensions to a subset of protocol implementations, so the following is now allowed:
let array = ["a", "b", "c", "a"]
extension SequenceType where Generator.Element: Comparable {
func distinct() -> [Generator.Element] {
var rtn: [Generator.Element] = []
for x in self {
if !rtn.contains(x) {
rtn.append(x)
}
}
return rtn
}
}
array.distinct() // ["a", "b", "c"]
Note how apple added SequenceType.contains using the same syntax.
Finally found out how to do it:
extension Array {
func contains<T : Equatable>(obj: T) -> Bool {
return self.filter({$0 as? T == obj}).count > 0
}
func distinct<T : Equatable>(_: T) -> T[] {
var rtn = T[]()
for x in self {
if !rtn.contains(x as T) {
rtn += x as T
}
}
return rtn
}
}
And usage/testing:
let a = [ 0, 1, 2, 3, 4, 5, 6, 1, 2, 3 ]
a.contains(0)
a.contains(99)
a.distinct(0)
Unfortunately, I can't figure out a way to do it without having to specify an argument which is subsequently ignored. The only reason it's there is to invoke the correct form of distinct. The major advantage of this approach for distinct seems to be that it's not dumping a common term like distinct into the global namespace. For the contains case it does seem more natural.
Another solution is to use the find(Array:[T], obj:T) function. It will return an optional Int, so what you could do is
if let foundResult = find(arr, obj) as Int
{
//obj is contained in arr
} else
{
//obj is not contained in arr.
}
As of Swift 2, this can be achieved with a protocol extension method,
e.g. on all types conforming to SequenceType where the sequence
elements conform to Equatable:
extension SequenceType where Generator.Element : Equatable {
func distinct() -> [Generator.Element] {
var rtn : [Generator.Element] = []
for elem in self {
if !rtn.contains(elem) {
rtn.append(elem)
}
}
return rtn
}
}
Example:
let items = [1, 2, 3, 2, 3, 4]
let unique = items.distinct()
print(unique) // [1, 2, 3, 4]
If the elements are further restricted to be Hashable then you
can take advantage of the Set type:
extension SequenceType where Generator.Element : Hashable {
func distinct() -> [Generator.Element] {
return Array(Set(self))
}
}