How to compare each element of array to other elements? - arrays

I need to find pairs in array, i wanted to do it with comparing arr[i] with others starting from arr[i+1] so i won't check for same value twice, but i can't get that going.
Here's what i've tried
func findPairs(_ ar: [Int]) -> Int {
var pairs = 0
for i in 0..<ar.count {
var k = i + 1
for k in 0..<ar.count {
if ar[i] == ar[k] {
pairs += 1
}
}
}
return pairs/2
}
Upd
to clarify, in the example i have, it was given as in array [1,2,3,1,2,3,4,5,1] we have 3 pairs [1,1] [2,2] [3,3]

You probably need to use i + 1 as the starting index in your inner loop, like that:
func findPairs(_ ar: [Int]) -> Int {
var pairs = 0
for i in 0..<ar.count {
let m = i + 1
for k in m..<ar.count {
if ar[i] == ar[k] {
pairs += 1
}
}
}
return pairs
}
Also, you can use another array to store the indexes of the pairs so that you do not use the same element for another pair:
func findPairs(_ ar: [Int]) -> Int {
var pairs = 0
var pairIndexes = [Int]()
for i in 0..<ar.count where !pairIndexes.contains(i) {
let m = i + 1
for k in m..<ar.count where !pairIndexes.contains(k) {
if ar[i] == ar[k] {
pairs += 1
pairIndexes.append(contentsOf: [i, k])
break
}
}
}
return pairs
}

The functional approach would be to get the total number of occurrences of the elements and sum half of it:
func findPairs(_ ar: [Int]) -> Int {
ar.reduce(into: [Int:Int]()) { $0[$1, default: 0] += 1 }.values.reduce(0) { $0 + $1/2 }
}
findPairs([1,2,3,1,2,3,4,5,1]) // 3
findPairs([4, 4, 4, 4, 4]) // 2
Or extending collection constraining the elements to hashable:
extension Collection where Element: Hashable {
var numberOfPairs: Int {
reduce(into: [Element:Int]()) { $0[$1, default: 0] += 1 }.values.reduce(0) { $0 + $1/2 }
}
}
[1,2,3,1,2,3,4,5,1].numberOfPairs // 3
[4, 4, 4, 4, 4].numberOfPairs // 2

I think you only need to find the number of pairs in the array.
So the following can work for you:
func findPairs(_ ar: [Int]) -> Int {
var pairs = 0
for i in 0..<ar.count {
for k in (i+1)..<ar.count {
if ar[i] == ar[k] {
pairs += 1
break
}
}
}
return pairs
}

Related

Idiomatic Kotlin way to find an element to the right of a pivot that's just greater than the pivot

I would like to write a computer program such that given an array of numbers and a pivot index, it returns the index of the smallest element to the right of the pivot that is just greater than the pivot.
For example: if the input is [1, 4, 7, 2, 5, 6] and the pivot is at index 1 i.e. element 4, then the output should be 4 which is the index of 5 because 5 is the smallest element to the right of 4 that is greater than 4.
The following code works
fun justGreater(nums: IntArray, pivotIndex: Int): Int {
var result = 0
var currBest = Int.MAX_VALUE
for (i in pivotIndex until nums.size) {
if (nums[i] > nums[pivotIndex] && nums[i] < currBest) {
result = i
currBest = nums[i]
}
}
return result
}
I would like to write this idiomatically and succinctly.
You can try following:
fun justGreater(nums: IntArray, pivotIndex: Int): Int {
return nums.withIndex()
.sortedBy { it.value }
.first { it.index > pivotIndex && it.value > nums[pivotIndex] }
.index
}
Another option:
fun justGreater(nums: IntArray, pivotIndex: Int): Int {
return nums.mapIndexed { index, number -> index to number }
.sortedBy { (_, number) -> number }
.first { (index, i) -> index > pivotIndex && i > nums[pivotIndex] }
.first // returns pair, so we need to get only index
}
One more option:
fun justGreater(nums: IntArray, pivotIndex: Int): Int {
val filteredArr = nums.sliceArray(pivotIndex + 1 until nums.size)
.filter { it > nums[pivotIndex] }
return nums.indexOf(filteredArr.min() ?: -1) // we return -1 in case item was not found
}
Just a little improvement
fun IntArray.justGreater(pivotIndex: Int): Int {
var result = 0
var currBest = Int.MAX_VALUE
for (i in pivotIndex until size) {
if (get(i) > get(pivotIndex) && get(i) < currBest) {
result = i
currBest = get(i)
}
}
return result
}
I think there is no shortcut function to decrease code
This returns the smallest closest value position to the right of pivot:
fun justGreater(nums: IntArray, pivotIndex: Int): Int {
val least = nums.asList()
.subList(pivotIndex + 1, nums.size)
.filter { it > nums[pivotIndex] }
.min()!!
return nums.indexOf(least)
}

Swift: Binary search for standard array?

I have a sorted array and want to do binary search on it.
So I'm asking if something is already available in Swift library like sort etc.? Or is there a type independend version available?
Of course I could write it by my own, but I like to avoid reinventing the wheel again.
Here's my favorite implementation of binary search. It's useful not only for finding the element but also for finding the insertion index. Details about assumed sorting order (ascending or descending) and behavior with respect to equal elements are controlled by providing a corresponding predicate (e.g. { $0 < x } vs { $0 > x } vs { $0 <= x } vs { $0 >= x }). The comment unambiguously says what exactly does it do.
extension RandomAccessCollection {
/// Finds such index N that predicate is true for all elements up to
/// but not including the index N, and is false for all elements
/// starting with index N.
/// Behavior is undefined if there is no such N.
func binarySearch(predicate: (Element) -> Bool) -> Index {
var low = startIndex
var high = endIndex
while low != high {
let mid = index(low, offsetBy: distance(from: low, to: high)/2)
if predicate(self[mid]) {
low = index(after: mid)
} else {
high = mid
}
}
return low
}
}
Example usage:
(0 ..< 778).binarySearch { $0 < 145 } // 145
Here's a generic way to use binary search:
func binarySearch<T:Comparable>(_ inputArr:Array<T>, _ searchItem: T) -> Int? {
var lowerIndex = 0
var upperIndex = inputArr.count - 1
while (true) {
let currentIndex = (lowerIndex + upperIndex)/2
if(inputArr[currentIndex] == searchItem) {
return currentIndex
} else if (lowerIndex > upperIndex) {
return nil
} else {
if (inputArr[currentIndex] > searchItem) {
upperIndex = currentIndex - 1
} else {
lowerIndex = currentIndex + 1
}
}
}
}
var myArray = [1,2,3,4,5,6,7,9,10]
if let searchIndex = binarySearch(myArray, 5) {
print("Element found on index: \(searchIndex)")
}
I use an extension on RandomAccessCollection implementing bisectToFirstIndex(where:) and taking a predicate.
It takes a test predicate, and returns the index of the first element to pass the test.
If there is no such index, it returns nil.
If the Collection is empty, it returns nil.
Example
let a = [1,2,3,4]
a.map{$0>=3}
// returns [false, false, true, true]
a.bisectToFirstIndex {$0>=3}
// returns 2
Important
You need to ensure test never returns a false for any index after an index it has said true for. This is equivalent to the usual precondition that binary search requires your data to be in order.
Specifically, you must not do a.bisectToFirstIndex {$0==3}. This will not work correctly.
Why?
bisectToFirstIndex is useful because it lets you find ranges of stuff in your data. By adjusting the test, you can find the lower and upper limits of "stuff".
Here's some data:
let a = [1,1,1, 2,2,2,2, 3, 4, 5]
We can find the Range of all the 2s like this…
let firstOf2s = a.bisectToFirstIndex { $ 0>= 2 }
let endOf2s = a.bisectToFirstIndex { $0 > 2 }
let rangeOf2s = firstOf2s ..< endOf2s
Example Application
I use this in an implementation of layoutAttributesForElementsInRect. My UICollectionViewCells are stored sorted vertically in an array. It's easy to write a pair of calls that will find all cells that are within a particular rectangle and exclude any others.
Code
extension RandomAccessCollection {
public func bisectToFirstIndex(where predicate: (Element) throws -> Bool) rethrows -> Index? {
var intervalStart = startIndex
var intervalEnd = endIndex
while intervalStart != intervalEnd {
let intervalLength = distance(from: intervalStart, to: intervalEnd)
guard intervalLength > 1 else {
return try predicate(self[intervalStart]) ? intervalStart : nil
}
let testIndex = index(intervalStart, offsetBy: (intervalLength - 1) / 2)
if try predicate(self[testIndex]) {
intervalEnd = index(after: testIndex)
}
else {
intervalStart = index(after: testIndex)
}
}
return nil
}
}
Updates…
The implementation here extends RandomAccessCollection and I've updated the code to build with the current Swift version (5 or something).
A Binary Search Caution
Binary searches are notoriously hard to correctly code. You really should read that link to find out just how common mistakes in their implementation are, but here is an extract:
When Jon Bentley assigned it as a problem in a course for professional programmers, he found that an astounding ninety percent failed to code a binary search correctly after several hours of working on it, and another study shows that accurate code for it is only found in five out of twenty textbooks. Furthermore, Bentley's own implementation of binary search, published in his 1986 book Programming Pearls, contains an error that remained undetected for over twenty years.
Given that last point, here is a test for this code. It passes! The testing isn't exhaustive – so there may certainly still be errors.
Tests
final class Collection_BisectTests: XCTestCase {
func test_bisect() {
for length in 0...100 {
let collection = 0 ... length
let targets = -4 ... length + 4
for toFind in targets {
let bisectIndex = collection.bisectToFirstIndex { $0 > toFind }
let expectIndex = collection.firstIndex { $0 > toFind }
XCTAssertEqual(bisectIndex, expectIndex, "Finding \(toFind+1) in 0...\(length)")
}
}
}
}
extension ArraySlice where Element: Comparable {
func binarySearch(_ value: Element) -> Int? {
guard !isEmpty else { return nil }
let midIndex = (startIndex + endIndex) / 2
if value == self[midIndex] {
return midIndex
} else if value > self[midIndex] {
return self[(midIndex + 1)...].binarySearch(value)
} else {
return self[..<midIndex].binarySearch(value)
}
}
}
extension Array where Element: Comparable {
func binarySearch(_ value: Element) -> Int? {
return self[0...].binarySearch(value)
}
}
This is, in my opinion, very readable and leverages the fact that Swift's ArraySlice is a view on Array and retains the same indexes as the original Array with which it shares the storage so, in absence of mutations (like in this case), it is therefore very efficient.
here is binary search using while syntax
func binarySearch<T: Comparable>(_ a: [T], key: T) -> Int? {
var lowerBound = 0
var upperBound = a.count
while lowerBound < upperBound {
let midIndex = lowerBound + (upperBound - lowerBound) / 2
if a[midIndex] == key {
return midIndex
} else if a[midIndex] < key {
lowerBound = midIndex + 1
} else {
upperBound = midIndex
}
}
return nil
}
Here is an implementation for a sorted array of strings.
var arr = ["a", "abc", "aabc", "aabbc", "aaabbbcc", "bacc", "bbcc", "bbbccc", "cb", "cbb", "cbbc", "d" , "defff", "deffz"]
func binarySearch(_ array: [String], value: String) -> String {
var firstIndex = 0
var lastIndex = array.count - 1
var wordToFind = "Not founded"
var count = 0
while firstIndex <= lastIndex {
count += 1
let middleIndex = (firstIndex + lastIndex) / 2
let middleValue = array[middleIndex]
if middleValue == value {
wordToFind = middleValue
return wordToFind
}
if value.localizedCompare(middleValue) == ComparisonResult.orderedDescending {
firstIndex = middleIndex + 1
}
if value.localizedCompare(middleValue) == ComparisonResult.orderedAscending {
print(middleValue)
lastIndex = middleIndex - 1
}
}
return wordToFind
}
//print d
print(binarySearch(arr, value: "d"))
Another implementation: if you want to have your structs or classes searchable without making them Comparable, make them BinarySearchable instead:
public protocol BinarySearchable {
associatedtype C: Comparable
var searchable: C { get }
}
public extension Array where Element: BinarySearchable {
func binarySearch(_ prefix: Element.C) -> Index {
var low = 0
var high = count
while low != high {
let mid = (low + high) / 2
if self[mid].searchable < prefix {
low = mid + 1
} else {
high = mid
}
}
return low
}
}
Example usage for a struct that should be sorted and searched by name:
struct Country: BinraySearchable {
var code: String
var name: String
var searchable: String { name }
}
// Suppose you have a list of countries sorted by `name`, you want to find
// the index of the first country whose name starts with "United", others
// will follow:
let index = listOfCountries.binarySearch("United")
And for completeness, here's a entirely pattern matching based implementation:
extension Collection where Element: Comparable {
func binarySearch(for element: Element) -> Index? {
switch index(startIndex, offsetBy: distance(from: startIndex, to: endIndex) / 2) {
case let i where i >= endIndex: return nil
case let i where self[i] == element: return i
case let i where self[i] > element: return self[..<i].binarySearch(for: element)
case let i: return self[index(after: i)..<endIndex].binarySearch(for: element)
}
}
}
The above code should work with any kind of collections, sliced or not sliced, zero offset-ed or non-zero offset-ed.
Here is how you create a binary search function in swift 5, in this example I assume that the item you are looking for is guaranteed to be in the list, however if your item is not guaranteed to be in the list then you can run this code to check first:
yourList.contains(yourItem) //will return true or false
Here is the binary search function:
override func viewDidLoad() {
super.viewDidLoad()
print(binarySearch(list: [1, 2, 4, 5, 6], num: 6)) //returns 4
}
func binarySearch(list: [Int], num: Int) -> Int //returns index of num
{
var firstIndex = 0
var lastIndex = list.count - 1
var middleIndex = (firstIndex + lastIndex) / 2
var middleValue = list[middleIndex]
while true //loop until we find the item we are looking for
{
middleIndex = (firstIndex + lastIndex) / 2 //getting the list's middle index
middleValue = list[middleIndex]
if middleValue > num
{
lastIndex = middleIndex - 1 //get the left side of the remaining list
}
else if middleValue < num
{
firstIndex = middleIndex + 1 //get the right side of the remaining list
}
else if middleValue == num
{
break //found the correct value so we can break out of the loop
}
}
return middleIndex
}
I have made a youtube video explaining this here
Here's a better implementation that returns more than one index, if there are more than 1 in the array.
extension Array where Element: Comparable {
/* Array Must be sorted */
func binarySearch(key: Element) -> [Index]? {
return self.binarySearch(key, initialIndex: 0)
}
private func binarySearch(key: Element, initialIndex: Index) -> [Index]? {
guard count > 0 else { return nil }
let midIndex = count / 2
let midElement = self[midIndex]
if key == midElement {
// Found!
let foundIndex = initialIndex + midIndex
var indexes = [foundIndex]
// Check neighbors for same values
// Check Left Side
var leftIndex = midIndex - 1
while leftIndex >= 0 {
//While there is still more items on the left to check
print(leftIndex)
if self[leftIndex] == key {
//If the items on the left is still matching key
indexes.append(leftIndex + initialIndex)
leftIndex--
} else {
// The item on the left is not identical to key
break
}
}
// Check Right side
var rightIndex = midIndex + 1
while rightIndex < count {
//While there is still more items on the left to check
if self[rightIndex] == key {
//If the items on the left is still matching key
indexes.append(rightIndex + initialIndex)
rightIndex++
} else {
// The item on the left is not identical to key
break
}
}
return indexes.sort{ return $0 < $1 }
}
if count == 1 {
guard let first = first else { return nil }
if first == key {
return [initialIndex]
}
return nil
}
if key < midElement {
return Array(self[0..<midIndex]).binarySearch(key, initialIndex: initialIndex + 0)
}
if key > midElement {
return Array(self[midIndex..<count]).binarySearch(key, initialIndex: initialIndex + midIndex)
}
return nil
}
}
By recursive binary search,
func binarySearch(data : [Int],search: Int,high : Int,low:Int) -> Int? {
if (low > high)
{
return nil
}
let mid = low + (low + high)/2
if (data[mid] == search) {
return mid
}
else if (search < data[mid]){
return binarySearch(data: data, search: search, high: high-1, low: low)
}else {
return binarySearch(data: data, search: search, high: high, low: low+1)
}
}
Input : let arry = Array(0...5) // [0,1,2,3,4,5]
print(binarySearch(data: arry, search: 0, high: arry.count-1, low: 0))
Here's a full example with several test cases for Swift 3.1. There is no chance that this is faster than the default implementation, but that's not the point. Array extension is at the bottom:
// BinarySearchTests.swift
// Created by Dan Rosenstark on 3/27/17
import XCTest
#testable import SwiftAlgos
class BinarySearchTests: XCTestCase {
let sortedArray : [Int] = [-25, 1, 2, 4, 6, 8, 10, 14, 15, 1000]
func test5() {
let traditional = sortedArray.index(of: 5)
let newImplementation = sortedArray.indexUsingBinarySearch(of: 5)
XCTAssertEqual(traditional, newImplementation)
}
func testMembers() {
for item in sortedArray {
let traditional = sortedArray.index(of: item)
let newImplementation = sortedArray.indexUsingBinarySearch(of: item)
XCTAssertEqual(traditional, newImplementation)
}
}
func testMembersAndNonMembers() {
for item in (-100...100) {
let traditional = sortedArray.index(of: item)
let newImplementation = sortedArray.indexUsingBinarySearch(of: item)
XCTAssertEqual(traditional, newImplementation)
}
}
func testSingleMember() {
let sortedArray = [50]
for item in (0...100) {
let traditional = sortedArray.index(of: item)
let newImplementation = sortedArray.indexUsingBinarySearch(of: item)
XCTAssertEqual(traditional, newImplementation)
}
}
func testEmptyArray() {
let sortedArray : [Int] = []
for item in (0...100) {
let traditional = sortedArray.index(of: item)
let newImplementation = sortedArray.indexUsingBinarySearch(of: item)
XCTAssertEqual(traditional, newImplementation)
}
}
}
extension Array where Element : Comparable {
// self must be a sorted Array
func indexUsingBinarySearch(of element: Element) -> Int? {
guard self.count > 0 else { return nil }
return binarySearch(for: element, minIndex: 0, maxIndex: self.count - 1)
}
private func binarySearch(for element: Element, minIndex: Int, maxIndex: Int) -> Int? {
let count = maxIndex - minIndex + 1
// if there are one or two elements, there is no futher recursion:
// stop and check one or both values (and return nil if neither)
if count == 1 {
return element == self[minIndex] ? minIndex : nil
} else if count == 2 {
switch element {
case self[minIndex]: return minIndex
case self[maxIndex]: return maxIndex
default: return nil
}
}
let breakPointIndex = Int(round(Double(maxIndex - minIndex) / 2.0)) + minIndex
let breakPoint = self[breakPointIndex]
let splitUp = (breakPoint < element)
let newMaxIndex : Int = splitUp ? maxIndex : breakPointIndex
let newMinIndex : Int = splitUp ? breakPointIndex : minIndex
return binarySearch(for: element, minIndex: newMinIndex, maxIndex: newMaxIndex)
}
}
This is quite homemade, so... caveat emptor. It does work and does do binary search.
Simple solution in Swift 5:
func binarySerach(list: [Int], item: Int) -> Int? {
var low = 0
var high = list.count - 1
while low <= high {
let mid = (low + high) / 2
let guess = list[mid]
if guess == item {
return mid
} else if guess > item {
high = mid - 1
} else {
low = mid + 1
}
}
return nil
}
let myList = [1,3,4,7,9]
print(binarySerach(list: myList, item: 9))
//Optional(4)
Details
Swift 5.2, Xcode 11.4 (11E146)
Solution
import Foundation
extension RandomAccessCollection where Element: Comparable {
private func binarySearchIteration(forIndexOf value: Element, in range: Range<Index>? = nil,
valueDetected: ((Index, _ in: Range<Index>) -> Index?)) -> Index? {
let range = range ?? startIndex..<endIndex
guard range.lowerBound < range.upperBound else { return nil }
let size = distance(from: range.lowerBound, to: range.upperBound)
let middle = index(range.lowerBound, offsetBy: size / 2)
switch self[middle] {
case value: return valueDetected(middle, range) ?? middle
case ..<value: return binarySearch(forIndexOf: value, in: index(after: middle)..<range.upperBound)
default: return binarySearch(forIndexOf: value, in: range.lowerBound..<middle)
}
}
func binarySearch(forIndexOf value: Element, in range: Range<Index>? = nil) -> Index? {
binarySearchIteration(forIndexOf: value, in: range) { currentIndex, _ in currentIndex }
}
func binarySearch(forFirstIndexOf value: Element, in range: Range<Index>? = nil) -> Index? {
binarySearchIteration(forIndexOf: value, in: range) { currentIndex, range in
binarySearch(forFirstIndexOf: value, in: range.lowerBound..<currentIndex)
}
}
func binarySearch(forLastIndexOf value: Element, in range: Range<Index>? = nil) -> Index? {
binarySearchIteration(forIndexOf: value, in: range) { currentIndex, range in
binarySearch(forFirstIndexOf: value, in: index(after: currentIndex)..<range.upperBound)
}
}
func binarySearch(forIndicesRangeOf value: Element, in range: Range<Index>? = nil) -> Range<Index>? {
let range = range ?? startIndex..<endIndex
guard range.lowerBound < range.upperBound else { return nil }
guard let currentIndex = binarySearchIteration(forIndexOf: value, in: range, valueDetected: { index, _ in index
}) else { return nil }
let firstIndex = binarySearch(forFirstIndexOf: value, in: range.lowerBound ..< index(after: currentIndex)) ?? currentIndex
let lastIndex = binarySearch(forFirstIndexOf: value, in: index(after: currentIndex) ..< range.upperBound) ?? currentIndex
return firstIndex..<index(after: lastIndex)
}
}
Usage
//let array = ["one", "two", "three", "three", "three", "three", "three", "four", "five", "five"]
//let value = "three"
let array = [1, 2, 3, 3, 3, 3, 3, 4, 5, 5]
let value = 3
print(array.binarySearch(forFirstIndexOf: value))
print(array.binarySearch(forLastIndexOf: value))
print(array.binarySearch(forIndicesRangeOf: value))
Tests
protocol _BinarySearchTestable: class where Collection: RandomAccessCollection, Collection.Element: Comparable {
associatedtype Collection
var array: Collection! { get set }
var elementToSearch: Collection.Element! { get set }
func testFindFirstIndexOfValueInCollection()
func testFindLastIndexOfValueInCollection()
func testFindIndicesRangeOfValueInCollection()
}
extension _BinarySearchTestable where Self: XCTest {
typealias Element = Collection.Element
typealias Index = Collection.Index
func _testFindFirstIndexOfValueInCollection() {
_testfindFirstIndex(comparableArray: array, testableArray: array)
}
func _testFindLastIndexOfValueInCollection() {
let index1 = array.lastIndex(of: elementToSearch)
let index2 = array.binarySearch(forLastIndexOf: elementToSearch)
_testElementsAreEqual(indexInComparableArray: index1, comparableArray: array,
indexInTestableArray: index2, testableArray: array)
}
func _testFindIndicesRangeOfValueInCollection() {
var range1: Range<Index>?
if let firstIndex = array.firstIndex(of: elementToSearch),
let lastIndex = array.lastIndex(of: elementToSearch) {
range1 = firstIndex ..< array.index(after: lastIndex)
}
let range2 = array.binarySearch(forIndicesRangeOf: elementToSearch)
XCTAssertEqual(range1, range2)
}
private func _testElementsAreEqual(indexInComparableArray: Index?, comparableArray: Collection,
indexInTestableArray: Index?, testableArray: Collection) {
XCTAssertEqual(indexInComparableArray, indexInTestableArray)
var valueInComparableArray: Element?
if let index = indexInComparableArray { valueInComparableArray = comparableArray[index] }
var valueInTestableArray: Element?
if let index = indexInComparableArray { valueInTestableArray = testableArray[index] }
XCTAssertEqual(valueInComparableArray, valueInTestableArray)
}
private func _testfindFirstIndex(comparableArray: Collection, testableArray: Collection) {
let index1 = comparableArray.firstIndex(of: elementToSearch)
let index2 = testableArray.binarySearch(forFirstIndexOf: elementToSearch)
_testElementsAreEqual(indexInComparableArray: index1, comparableArray: comparableArray,
indexInTestableArray: index2, testableArray: testableArray)
}
}
class TestsInEmptyArray: XCTestCase, _BinarySearchTestable {
var array: [String]!
var elementToSearch: String!
override func setUp() {
array = []
elementToSearch = "value"
}
func testFindFirstIndexOfValueInCollection() { _testFindFirstIndexOfValueInCollection() }
func testFindLastIndexOfValueInCollection() { _testFindLastIndexOfValueInCollection() }
func testFindIndicesRangeOfValueInCollection() { _testFindIndicesRangeOfValueInCollection() }
}
class TestsInArray: XCTestCase, _BinarySearchTestable {
var array: [Int]!
var elementToSearch: Int!
override func setUp() {
array = [1, 2, 3, 3, 3, 3, 3, 4, 5, 5]
elementToSearch = 3
}
func testFindFirstIndexOfValueInCollection() { _testFindFirstIndexOfValueInCollection() }
func testFindLastIndexOfValueInCollection() { _testFindLastIndexOfValueInCollection() }
func testFindIndicesRangeOfValueInCollection() { _testFindIndicesRangeOfValueInCollection() }
}
class TestsInArrayWithOneElement: XCTestCase, _BinarySearchTestable {
var array: [Date]!
var elementToSearch: Date!
override func setUp() {
let date = Date()
array = [date]
elementToSearch = date
}
func testFindFirstIndexOfValueInCollection() { _testFindFirstIndexOfValueInCollection() }
func testFindLastIndexOfValueInCollection() { _testFindLastIndexOfValueInCollection() }
func testFindIndicesRangeOfValueInCollection() { _testFindIndicesRangeOfValueInCollection() }
}

for loop with Array2D<Type>(columns: NumColumns, rows: NumRows) [duplicate]

How would I go about implementing a custom enumerate function that makes something like this work (Swift 2):
for ((column, row), item) in Array2D.enumerate() { ... }
In my simple Array2D struct:
struct Array2D<T> : SequenceType {
let columns: Int
let rows: Int
private var array: Array<T?>
init(columns: Int, rows: Int) {
self.columns = columns
self.rows = rows
array = Array(count: rows*columns, repeatedValue: nil)
}
subscript(column: Int, row: Int) -> T? {
get {
return array[columns*row + column]
}
set {
array[columns*row + column] = newValue
}
}
func generate() -> AnyGenerator<T?> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return item
}
}
}
I couldn't find any good explanation on implementing an enumerate function in Swift
The enumerate() function in Swift returns integers starting from 0 for the first part of its tuple. Those have nothing to do with the sequence you're enumerating over. So, for instance, this won't work:
let word = "hello".characters
for (index, letter) in word.enumerate() {
print(word[index])
}
Because the indices of a characterView are String.Indexs.
So there are several ways to get what you're going for. The first is to just overload enumerate() for your struct. Again, there are a few days you could do this. First off, how about a function that uses your own generator, and uses its own logic to figure out the coordinates. This could work:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
let g = self.generate()
var coord = -1
return anyGenerator {
g.next().map { ((++coord % self.columns, coord / self.columns), $0) }
}
}
But you're duplicating code there, especially from your generate method. Seeing you're already using coordinates to return each element, why not just have your enumerate method be the default, and your generate method call on that. Something like this:
// Original generate method, now returns the coords it used
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var column = 0
var row = 0
return anyGenerator() {
guard row < self.rows else {
return nil
}
let item = self[column, row]
if ++column == self.columns {
column = 0
++row
}
return ((column, row), item)
}
}
// uses enumerate, ignores coords
func generate() -> AnyGenerator<T?> {
let g = self.enumerate()
return anyGenerator {
g.next().map { $1 }
}
}
If you wanted to go a little overboard, you could write an enumerate function that enumerates the specific indices of its base. Call it specEnumerate:
public struct SpecEnumerateGen<Base : CollectionType> : GeneratorType {
private var eG: Base.Generator
private let sI: Base.Index
private var i : Base.Index?
public mutating func next() -> (Base.Index, Base.Generator.Element)? {
i?._successorInPlace() ?? {self.i = self.sI}()
return eG.next().map { (i!, $0) }
}
private init(g: Base.Generator, i: Base.Index) {
self.eG = g
self.sI = i
self.i = nil
}
}
public struct SpecEnumerateSeq<Base : CollectionType> : SequenceType {
private let col: Base
public func generate() -> SpecEnumerateGen<Base> {
return SpecEnumerateGen(g: col.generate(), i: col.startIndex)
}
}
public extension CollectionType {
func specEnumerate() -> SpecEnumerateSeq<Self> {
return SpecEnumerateSeq(col: self)
}
}
With this function, this would work:
let word = "hello".characters
for (index, letter) in word.specEnumerate() {
print(word[index])
}
But your matrix struct is still a SequenceType, with no specific indices. For that, you'll have to implement your own MatrixIndex:
public struct MatrixIndex: BidirectionalIndexType {
public let x, y : Int
private let columns: Int
public func successor() -> MatrixIndex {
return (x + 1 == columns) ?
MatrixIndex(x: 0, y: y + 1, columns: columns) :
MatrixIndex(x: x + 1, y: y, columns: columns)
}
public func predecessor() -> MatrixIndex {
return (x == 0) ?
MatrixIndex(x: columns - 1, y: y - 1, columns: columns) :
MatrixIndex(x: x - 1, y: y, columns: columns)
}
}
public func == (lhs: MatrixIndex, rhs: MatrixIndex) -> Bool {
return lhs.x == rhs.x && lhs.y == rhs.y
}
extension MatrixIndex : CustomDebugStringConvertible {
public var debugDescription: String {
return "\(x), \(y)"
}
}
extension MatrixIndex: RandomAccessIndexType {
public func advancedBy(n: Int) -> MatrixIndex {
let total = (y * columns) + x + n
return MatrixIndex(x: total % columns, y: total / columns, columns: columns)
}
public func distanceTo(other: MatrixIndex) -> Int {
return (other.x - x) + (other.y - y) * columns
}
}
Right. Now you'll need another matrix struct:
public struct Matrix2D<T> : MutableCollectionType {
public var contents: [[T]]
public subscript(index: MatrixIndex) -> T {
get {
return contents[index.y][index.x]
} set {
self.contents[index.y][index.x] = newValue
}
}
public var count: Int { return contents[0].count * contents.count }
public var startIndex: MatrixIndex {
return MatrixIndex(x: 0, y: 0, columns: contents[0].count)
}
public var endIndex: MatrixIndex {
return MatrixIndex(x: 0, y: contents.endIndex, columns: contents[0].count)
}
}
Right. So now, after all of that, this works:
let myMatrix = Matrix2D(contents: [[1, 2], [3, 4]])
for (coordinate, value) in myMatrix.specEnumerate() {
value == myMatrix[coordinate] // True every time
}
It might suffice defining your own enumerate taking advantage of the one you already have:
func enumerate() -> AnyGenerator<((Int, Int), T?)> {
var index = 0
var g = array.generate()
return anyGenerator() {
if let item = g.next() {
let column = index % self.columns
let row = index / self.columns
++index
return ((column, row) , item)
}
return nil
}
}
Notice in this case you could avoid conforming to SequenceType since I use generate from the private array. Anyway it could be consistent to do so.
Here is how then you could use it:
var a2d = Array2D<Int>(columns: 2, rows: 4)
a2d[0,1] = 4
for ((column, row), item) in a2d.enumerate() {
print ("[\(column) : \(row)] = \(item)")
}
Hope this helps

Swift modify Int array for InsertionSort algorithm

I'm very new to Swift and I wanted to know how I'm supposed to modify an Int contained in my Int[]? I made it like I'd do it in Java but it, obviously, doesn't work: I get a Cannot assign to immutable value of type 'Int' compilation error.
Here is my code:
import Foundation
func createRandomArray(length: Int) -> [Int]{
var random = [Int]()
for index in 0...length{
random.append(Int(arc4random_uniform(100)))
}
return random
}
func insertionSort(toSort: [Int]) -> [Int]{
var length = toSort.count
for index in 1...length-1{
var key = toSort[index]
var previous = index-1
while(previous>0 && toSort[previous]>key){
// ERROR IS THERE
toSort[previous+1] = toSort[previous]
previous--
}
}
return toSort
}
var array = createRandomArray(10)
print(array)
print(insertionSort(array))
I thought that using a var instead of let will give a mutable object so that's why I'm a bit lost.
Thanks for help
EDIT:
I got this working answer yet, thanks to #vacawama:
import Foundation
func createRandomArray(length: Int) -> [Int]{
var random = [Int]()
for index in 0...length{
random.append(Int(arc4random_uniform(100)))
}
return random
}
func insertionSort(var toSort: [Int]) -> [Int]{
for firstIterator in 1...toSort.count-1{
var currentValue = toSort[firstIterator]
var previousPosition = firstIterator-1
while(previousPosition>=0 && toSort[previousPosition]>currentValue){
swap(&toSort[previousPosition+1], &toSort[previousPosition])
previousPosition--
}
}
return toSort
}
var array = createRandomArray(10)
print(array)
print(insertionSort(array))
Updated Answer for Swift 5.x and Beyond
Swift has had many changes in the 7 years since I answered this question. It is no longer valid to insert var into the function header to make an array modifiable. The modern way to do that is to make var toSort = toSort the first line of the function body.
Here is a modification of the OP's code with modern Swift updates:
func createRandomArray(_ length: Int) -> [Int] {
var random = [Int]()
for _ in 0..<length {
random.append(Int.random(in: 0..<100))
}
return random
}
func insertionSort(_ toSort: [Int]) -> [Int] {
var toSort = toSort
for firstIterator in 1..<toSort.count {
let currentValue = toSort[firstIterator]
var previousPosition = firstIterator - 1
while (previousPosition >= 0 && toSort[previousPosition] > currentValue) {
toSort.swapAt(previousPosition + 1, previousPosition)
previousPosition -= 1
}
}
return toSort
}
var array = createRandomArray(10)
print(array)
print(insertionSort(array))
A shorter version of createRandomArray:
func createRandomArray(_ length: Int) -> [Int] {
(0..<length).map { _ in .random(in: 0..<100) }
}
Note: Your insertionSort() will crash if it is passed an empty array. Add this guard statement to the start of the function body to prevent that:
guard !toSort.isEmpty else { return toSort }
Original Answer (now obsolete) for Swift 1.0
By default, array parameters are immutable within the called function. If you want to modify the copy of the array that is passed to insertionSort, add var before toSort in the function header.
func insertionSort(var toSort: [Int]) -> [Int]{
I played with the following using swift 3. Hope it'll help some people who come here.
import Cocoa
func ints(cnt: Int, ceiling: Int) -> [Int] {
var arr = [Int]()
for _ in 0 ..< cnt {
arr.append(Int(arc4random_uniform(UInt32(ceiling))))
}
return arr
}
func insertion(arr: inout [Int]) {
for i in 1..<arr.count {
var j = i
let x = arr[i]
while j > 0 && arr[j - 1] > x {
arr[j] = arr[j - 1]
j -= 1
}
arr[j] = x
}
}
let a = ints(cnt: 10, ceiling: 100)
print(a)
var b = a
insertion(arr: &b)
print(b)
output:
[13, 30, 68, 19, 1, 4, 28, 65, 96, 13]
[1, 4, 13, 13, 19, 28, 30, 65, 68, 96]
For comparison, here is an implementaion in java:
void insertionSort(int[] arr) {
for(int i = 1; i < arr.length; i++) {
int x = arr[i];
int j = i;
while(j > 0 && arr[j - 1] > x) {
arr[j] = arr[j - 1];
j--;
}
arr[j] = x;
}
}
struct InsertionSort {
static func sort(data: Array<Int> = [5,9,1,8,2,4,3,1]) {
var data = data
for (i, e) in data.enumerated() where i > 0 && e < data[i - 1] {
traverseBackwardAndSwap(i, &data)
}
printData(data)
}
private static func traverseBackwardAndSwap(_ i: Int, _ data: inout [Int]) {
for i in (0...i).reversed() where i > 0 && data[i] < data[i-1] {
let temp = data[i]
data[i] = data[i-1]
data[i-1] = temp
}
}
private static func printData(_ data: [Int]) {
for e in data {
print("\(e)")
}
}
}
Swift 5: Generic Insertion sort
func insertionSort<U: Comparable>(with array: inout [U]) -> [U] {
for i in 1..<array.count {
let temp = array[i]
var insertionIndex = i
for j in (0...i).reversed() where j>0 && temp < array[j-1] {
array[j] = array[j-1]
insertionIndex = j-1
}
array[insertionIndex] = temp
}
return array
}
Input:-
var intArray = [8, 3, 5, 10, 4, -1, 17, 3, 18, 10]
var floatArray = [12.231, 12.23, 14.5, 3.4, 67.899, 0.0, -1.234]
var doubleArray = [123.43555, 123.1223332, -121.2212, 23.343434, 1.232434]
var stringArray = ["Ratheesh", "Srini", "Thangu", "Muthu", "Gopi"]
print(insertionSort(with: &intArray))
print(insertionSort(with: &floatArray))
print(insertionSort(with: &doubleArray))
print(insertionSort(with: &stringArray))
Output:-
[-1, 3, 3, 4, 5, 8, 10, 10, 17, 18]
[-1.234, 0.0, 3.4, 12.23, 12.231, 14.5, 67.899]
[-121.2212, 1.232434, 23.343434, 123.1223332, 123.43555]
["Gopi", "Muthu", "Ratheesh", "Srini", "Thangu"]

Add exactly 2 equal Elements to an array

I'm trying to add a random number (1...8) into an array.
I want to do this 16 times. The clue is, every number should only be in there twice. I got it working so far, but I don't think this is a clean way to do it. And the way I did it, it is not scaleable. If i wanted it to be, let's say for example 24 elements, and all of them 3 times, I'd have to rewrite all the code. Do You have an idea how to fix that? Thanks in advance!
var Numbers: [Int] = []
var randomNumber: Int = 0
let size: Int = 16
var index1 = 0
var index2 = 0
var index3 = 0
var index4 = 0
var index5 = 0
var index6 = 0
var index7 = 0
var index8 = 0
// Methods / Functions
func createRandomNumber() {
randomNumber = Int(arc4random() % 8 + 1)
}
func checkTwins() {
switch randomNumber {
case 1:
index1++
if index1 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 2:
index2++
if index2 <= 2{
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 3:
index3++
if index3 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 4:
index4++
if index4 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 5:
index5++
if index5 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 6:
index6++
if index6 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 7:
index7++
if index7 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
case 8:
index8++
if index8 <= 2 {
Numbers.append(randomNumber)
}
else {
addRandomNumbertoArray()
}
default: println("Generated Number out of Index")
}
}
func addRandomNumbertoArray() {
createRandomNumber()
checkTwins()
}
func fillUpArray() {
for _ in 1...size {
addRandomNumbertoArray()
}
}
// Calls
fillUpArray()
println(Numbers)
This was written in Swift Playground
What you can do is: First fill an array containing each of the
number 1, ..., 8 twice:
var array : [Int] = []
for i in 1 ... 8 {
array.extend(Repeat(count: 2, repeatedValue: i))
}
and then shuffle the array randomly:
array.shuffle()
where shuffle() is a Fisher-Yates shuffle.
A Swift implementation can be found in
How do I shuffle an array in Swift?:
extension Array {
mutating func shuffle() {
for i in 0..<(count - 1) {
let j = Int(arc4random_uniform(UInt32(count - i))) + i
swap(&self[i], &self[j])
}
}
}
This scales without problems to larger arrays and more repeated
elements.

Resources