Using Swift Get array of non repeating numbers from array of numbers - swift

Example.
let numArray = [1,2,3,3,4,5,5]
From above array create array of non- repeating number using swift. But I don't want to use Set.
Expected output is [1,2,4]

You may try the following:
let numArray = [1, 2, 3, 3, 4, 5, 5]
// Group by value
let grouped = Dictionary(grouping: numArray, by: { $0 })
// Filter by its count, convert back to Array and sort
let unique = Array(grouped.filter { $1.count == 1 }.map(\.key)).sorted()
print(unique) // [1, 2, 4]
Here is an alternative way without using higher order functions:
let numArray = [1, 2, 3, 3, 4, 5, 5]
// Group by value
let grouped = Dictionary(grouping: numArray, by: { $0 })
var uniqueArray = [Int]()
for (key, value) in grouped {
if value.count == 1 {
uniqueArray.append(key)
}
}
print(uniqueArray.sorted()) // [1, 2, 4]

Related

Sorting with higher order functions: Giving precedence to one element

With an unordered array of Ints as such:
let numbers = [4, 3, 1, 5, 2]
Is it possible in Swift, using .sorted { }, to order the array with one item prioritised and placed in the first index of the array. So instead of returning [1, 2, 3, 4, 5] we could get [3, 1, 2, 4, 5]?
You can declare a function like this :
func sort(_ array: [Int], prioritizing n: Int) -> [Int] {
var copy = array
let pivot = copy.partition { $0 != n }
copy[pivot...].sort()
return copy
}
Which uses the partition(by:) function.
You could use it like so:
let numbers = [4, 3, 1, 5, 2]
let specialNumber = 3
sort(numbers, prioritizing: specialNumber) //[3, 1, 2, 4, 5]
Here are some test cases :
sort([3, 3, 3], prioritizing: 3) //[3, 3, 3]
sort([9, 4, 1, 5, 2], prioritizing: 3) //[1, 2, 4, 5, 9]
Here an alternative solution that uses sorted(by:) only :
let numbers = [4, 3, 1, 5, 2]
let vipNumber = 3
let result = numbers.sorted {
($0 == vipNumber ? Int.min : $0) < ($1 == vipNumber ? Int.min : $1)
}
print(result) //[3, 1, 2, 4, 5]

Cannot assign value of type '()' to type '[Int]'

Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A.
Input: [3,1,2,4]
Output: [2,4,3,1]
The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted.
I have implemented following, but it throws me an error
Line 17: cannot assign value of type '()' to type '[Int]'
By the way, are there more elegant solution?
class Solution {
func sortArrayByParity(_ A: [Int]) -> [Int] {
var oddTemp :[Int] = []
var evenTemp :[Int] = []
for a in A
{
if a%2 == 0
{
evenTemp.append(a)
}
else
{
oddTemp.append(a)
}
}
// error is thrown in the following
return evenTemp += oddTemp
}
}
If you want to mutate the original array:
var a = [3, 1, 2, 4]
a.sort(by: { $0 % 2 < $1 % 2 })
print(a) //prints [2, 4, 3, 1]
If you prefer immutability:
let a = [3, 1, 2, 4]
let result: [Int] = a.sorted(by: { $0 % 2 < $1 % 2})
print(result) //prints [2, 4, 3, 1]
Other solution:
let a = [3,1,2,4]
let result: [Int] = a.reduce(into: []) { accumulator, element in
let newIndex = element % 2 == 0 ? accumulator.startIndex : accumulator.endIndex
accumulator.insert(element, at: newIndex)
}
print(result)
prints [4, 2, 3, 1]
return evenTemp + oddTemp
does what you want
Mutable arrays can be sorted in-place, e.g. for your example you could do
var a = [0, 3, 1, 2, 4, 5, 6, 6, 7, 7, 8,9,10,10,11,11,11,11,12]
a.sort { $1 % 2 > $0 % 2 }
print(a) // [0, 2, 4, 6, 6, 8, 10, 10, 12, 3, 1, 5, 7, 7, 9, 11, 11, 11, 11]
The += operator mutates the left hand side operand and its return value is Void. You need to separate the concanation of the arrays and the return statement into separate lines.
evenTemp += oddTemp
return evenTemp
This
evenTemp += oddTemp
doesn't return anything
evenTemp += oddTemp
return evenTemp

Map and split values in array

How I can map a array and, in same closure, split the values in two variables?
This code work, but, I want use only one closure, not three.
let array = [1, 2, 3, 4]
let a = array.map { v -> (Int, Int) in
(v * 2, v * 10)
}
let x = a.map { $0.0 }
let y = a.map { $0.1 }
Here's a possibly less readable, but arguably more functional-style solution (immutable arrays, no for-each loop, pure function that only acts on its inputs and doesn't create side effects outside the closure):
let array = [1, 2, 3, 4]
let (x, y) = array.reduce(([Int](), [Int]())){ (result, int) in (result.0 + [int*2], result.1 + [int*10]) }
print(x) // [2, 4, 6, 8]
print(y) // [10, 20, 30, 40]
It also meets your requirement of using just one closure
Try this:
let array = [1, 2, 3, 4]
var x = [Int]()
var y = [Int]()
array.forEach() {
x.append($0 * 2)
y.append($0 * 10)
}
print(x[0]) // 2
print(y[0]) // 10
...
You can use tuple assignment to achieve this:
let array = [1, 2, 3, 4]
let (x, y) = (array.map{$0 * 2}, array.map{$0 * 10})
print(x, y)

Optimal Way to Remove Unique Values from Two Arrays

I have two arrays of [PFObjects].
For example (simplified):
arr1: [PFObject] = [1, 2, 3, 4, 5, 6, 7, 8]
arr2: [PFObject] = [1, 2, 3, 4, 5]
What is the optimal way to compare arr1 with arr2 and only keep the duplicates (remove unique values).
So that arr1 looks like:
arr1 = [1, 2, 3, 4, 5]
let array = arr1.filter { arr2.contains($0) }
voilĂ  !
First solution (Looping):
var arr1: [PFObject] = [1, 2, 3, 4, 5, 6, 7, 8]
var arr2: [PFObject] = [1, 2, 3, 4, 5]
var temp: [PFObject] = []
for element in arr1 {
if contains(arr2, element) {
temp.append(element)
}
}
arr1 = temp
You can loop over the first array, check if each element is contained in the array, if it is, you can add it to a temporary array. After looping over every element you can replace the value of the first array with your temporary array.
Second solution (Sets):
var arr1: [PFObject] = [1, 2, 3, 4, 5, 6, 7, 8]
var arr2: [PFObject] = [1, 2, 3, 4, 5]
let set1 = Set(arr1)
let set2 = Set(arr2)
var arr1= Array(set1.intersect(set2)) // [1, 2, 3, 4, 5]
What you do here is:
First you create sets from your arrays
Then you use the intersect method from sets to determine common elements
Finally you transform your set to an array before passing it back to arr1
Of course since you will be using sets, duplicate elements will be lost but I'm guessing that shouldn't be a problem in your case
Third solution (filter):
From the answer of Pham Hoan you can use filters to obtain a subset of arr1, the closure gives you the conditions, here it is that arr2 contains the value you are looking at.
let array = arr1.filter { arr2.contains($0) }
This is obviously the shorter solution in terms of code length.
I do not know which technique would be more efficient if you have very large arrays however.

Remove multiple indices from array

I have an array and I want to remove a bunch of indices
var arr = [0,1,2,3,4,5,6]
var rmIndices = [1,4,5]
What is the best way to remove indices 1,4,5 from arr?
Note that PermutationGenerator is going away in Swift 3 and also doesn't keep the ordering the same, though perhaps it did at one time. Using the accepted answer results in [2, 6, 0, 3] which may be unexpected. A couple of alternative approaches that give the expected result of [0, 2, 3, 6] are:
let flatArr = arr.enumerate().flatMap { rmIndices.contains($0.0) ? nil : $0.1 }
or
let filterArr = arr.enumerate().filter({ !rmIndices.contains($0.0) }).map { $0.1 }
Rather than a list of indices to remove, it may be easier to have a list of indices to keep, which you can do using the Set type:
let rmIndices = [1,4,5]
let keepIndices = Set(arr.indices).subtract([1,4,5])
Then you can use PermutationGenerator to create a fresh array of just those indices:
arr = Array(PermutationGenerator(elements: arr, indices: keepIndices))
rmIndices.sort({ $1 < $0 })
for index in rmIndices
{
arr.removeAtIndex(index)
}
Note that I've sorted the indices in descending order. This is because everytime you remove an element E, the indices of the elements beyond E reduce by one.
For Swift 3
var arr = [0,1,2,3,4,5,6]
let rmIndices = [1,4,5]
arr = arr.filter{ !rmIndices.contains($0) }
print(arr)
if you want to produce output very fastly then you can use
var arr = [0,1,2,3,4,5,6]
let rmIndices = [1,4,5]
arr = Array(Set(arr).subtracting(rmIndices))
print(array)
But it will change order of your array
Remove elements using indexes array:
Array of Strings and indexes
let animals = ["cats", "dogs", "chimps", "moose", "squarrel", "cow"]
let indexAnimals = [0, 3, 4]
let arrayRemainingAnimals = animals
.enumerated()
.filter { !indexAnimals.contains($0.offset) }
.map { $0.element }
print(arrayRemainingAnimals)
//result - ["dogs", "chimps", "cow"]
Array of Integers and indexes
var numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
let indexesToRemove = [3, 5, 8, 12]
numbers = numbers
.enumerated()
.filter { !indexesToRemove.contains($0.offset) }
.map { $0.element }
print(numbers)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Remove elements using element value of another array
Arrays of integers
let arrayResult = numbers.filter { element in
return !indexesToRemove.contains(element)
}
print(arrayResult)
//result - [0, 1, 2, 4, 6, 7, 9, 10, 11]
Arrays of strings
let arrayLetters = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]
let arrayRemoveLetters = ["a", "e", "g", "h"]
let arrayRemainingLetters = arrayLetters.filter {
!arrayRemoveLetters.contains($0)
}
print(arrayRemainingLetters)
//result - ["b", "c", "d", "f", "i"]
In Swift 4:
let newArr = arr.enumerated().compactMap {
rmIndices.contains($0.0) ? nil : $0.1
}
enumerated() generates (index, value) pairs
compactMap concatenates non-nil values
In the closure, $0.0 is the index (first element of enumerated pair) as $0.1$ is the value
compactMap gathers values whose indices are not found in rmIndices
The problem with flatmap is that it gives incorrect results if your array contains optionals.
The following is much faster than the functional style solutions provided and works with optionals. You just have to make sure rmIndices is sorted and unique. It's also fairly language agnostic.
var numRemoved: Int = 0
for index in rmIndices {
let indexToRemove = index - numRemoved
arr.remove(at: indexToRemove)
numRemoved += 1
}
If you need to make sure rmIndices is sorted and unique:
rmIndices = Set(rmIndices).sorted()
Using XCTest to remove 500 elements (including the operation to ensure uniqueness and sorted):
0.006 sec
vs.
arr.enumerated().filter({ !rmIndices.contains($0.0) }).map { $0.1 }:
0.206 sec
I use this as an extension on Array
extension Array {
mutating func remove(at indices: [Int]) {
let rmIndices = Set(indices).sorted()
var numRemoved: Int = 0
for index in rmIndices {
let indexToRemove = index - numRemoved
self.remove(at: indexToRemove)
numRemoved += 1
}
}
}
Using lodash https://lodash.com/
var arr = [0,1,2,3,4,5,6]
var rmIndices = [1,4,5]
_.pullAt(arr, rmIndices);