Skip to content

Instantly share code, notes, and snippets.

@a-voronov
Last active November 8, 2019 00:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-voronov/9d96abc5696115c98a868de50f4ef9b1 to your computer and use it in GitHub Desktop.
Save a-voronov/9d96abc5696115c98a868de50f4ef9b1 to your computer and use it in GitHub Desktop.
Lightweight Data-Structure for Storing One or More Elements πŸƒ
public indirect enum OneOrMore<T> {
case one(T)
case more(T, Self)
}
// MARK: Creation simplified
public extension OneOrMore {
static func few(_ head: T, _ tail: T...) -> OneOrMore {
few(head, tail)
}
static func few<S>(_ head: T, _ tail: S) -> OneOrMore where S: Sequence, S.Element == T {
var many: OneOrMore = .one(head)
for value in tail {
many = .more(value, many)
}
return many
}
}
// MARK: Adding elements
public extension OneOrMore {
mutating func add(_ other: T) {
self = adding(other)
}
func adding(_ other: T) -> Self {
.more(other, self)
}
}
// MARK: Array representation
public extension OneOrMore {
var array: [T] {
switch self {
case let .one(value):
return [value]
case let .more(value, other):
var copy = other.array
copy.append(value)
return copy
}
}
}
// MARK: Set representation
public extension OneOrMore where T: Hashable {
var set: Set<T> {
switch self {
case let .one(value):
return [value]
case let .more(value, other):
var copy = other.set
copy.insert(value)
return copy
}
}
}
// MARK: Equatable & Hashable
extension OneOrMore: Equatable where T: Equatable {}
extension OneOrMore: Hashable where T: Hashable {}
// MARK: Debugging
extension OneOrMore: CustomDebugStringConvertible {
public var debugDescription: String {
array.debugDescription
}
}
// MARK: Decompose collection to map into OneOrMore
extension Collection {
func decompose() -> (head: Element, tail: [Element])? {
first.map { head in
(head: head, tail: Array(dropFirst()))
}
}
}
@a-voronov
Copy link
Author

Example

let xs = [1, 2, 2, 3, 4]
let ys = xs.decompose().map(OneOrMore.few)
ys?.array // 1, 2, 2, 3, 4
ys?.set   // 1, 2, 3, 4

Note

Not intended for big data-sets, as it takes N steps to compose into user-friendly representation.
However fits good for something small like errors or validations sets, etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment