Skip to content

Instantly share code, notes, and snippets.

@surakamy
Last active February 12, 2018 20:53
Show Gist options
  • Save surakamy/5e84d96e2fe7d21cb31e1438538dee02 to your computer and use it in GitHub Desktop.
Save surakamy/5e84d96e2fe7d21cb31e1438538dee02 to your computer and use it in GitHub Desktop.
Extension to Array - split at indices
extension Array {
/// Returns the longest possible subsequences of the collection, in order,
/// that don't contain elements at indices provided.
///
/// The resulting array consists of at most `maxSplits + 1` subsequences.
/// Elements that are used to split the sequence are not returned as part of
/// any subsequence.
///
/// - Parameters:
/// - maxSplits: The maximum number of times to split the collection, or
/// one less than the number of subsequences to return. If
/// `maxSplits + 1` subsequences are returned, the last one is a suffix
/// of the original collection containing the remaining elements.
/// `maxSplits` must be greater than or equal to zero. The default value
/// is `Int.max`.
/// - omittingEmptySubsequences: If `false`, an empty subsequence is
/// returned in the result for each pair of consecutive elements
/// satisfying the `isSeparator` predicate and for each element at the
/// start or end of the collection satisfying the `isSeparator`
/// predicate. The default value is `true`.
/// - indices: variadic parameter containing indices at which collection should be splitted. Elements at these indices are removed from resulting collections. Indices out of bounds are ignored.
/// - Returns: An array of subsequences, split from this collection's
/// elements.
func split(maxSplits: Int = Int.max,
omittingEmptySubsequences: Bool = true,
at indices: Int...) -> [ArraySlice<Element>]
{
// Prepare safe indices
var safeIndices = indices
safeIndices = indices.filter{ startIndex...endIndex ~= $0 }
let skip = safeIndices.count - maxSplits
if skip > 0 { safeIndices.removeLast(skip) }
safeIndices.append(endIndex)
//Slide though array by indices forming slices
var slices: [ArraySlice<Array.Element>] = []
var lo = startIndex
for idx in safeIndices {
slices.append(self[lo..<idx])
lo = index(after: idx)
}
if omittingEmptySubsequences {
return slices.flatMap{ $0.isEmpty ? nil : $0 }
}
return slices
}
}
let numbers = Array(1...10)
numbers.split(at: 5)
//[[1, 2, 3, 4, 5], [7, 8, 9, 10]]
numbers.split(at: 5, 6, 8)
//[[1, 2, 3, 4, 5], [8], [10]]
numbers.split(omittingEmptySubsequences: false, at: 1, 2)
//[[1], ArraySlice([]), [4, 5, 6, 7, 8, 9, 10]]
numbers.split(maxSplits: 1, at: 5, 6, 8)
//[[1, 2, 3, 4, 5], [7, 8, 9, 10]]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment