import Foundation

extension Collection {

    func sorted<T>(ascending: Bool = true, using conversion: (Element) -> T) -> [Element] where T: Comparable {
        guard ascending else {
            return sorted { conversion($0) > conversion($1) }
        }
        return sorted { conversion($0) < conversion($1) }
    }

    func count(where predicate: (Element) throws -> Bool) rethrows -> Int {
        try reduce(0) { count, element in
            try predicate(element) ? count + 1 : count
        }
    }

    func countThrows(where predicate: (Element) throws -> Void) -> Int {
        reduce(0) { count, element in
            do {
                try predicate(element)
                return count
            } catch {
                return count + 1
            }
        }

    }
}

extension Collection where Element: Collection, Element.Element: Hashable {

    func union() -> Set<Element.Element> {
        reduce(into: []) { $0.formUnion($1) }
    }
}

extension Collection where Element: Hashable {

    func asSet() -> Set<Element> {
        Set(self)
    }
}

extension RangeReplaceableCollection where Element: Comparable {


    mutating func insertSorted(_ element: Element) {
        let index = firstIndex(where: { $0 > element }) ?? endIndex
        insert(element, at: index)
    }
}
