unresolved identifier - for in loop logic - swift

This is a sort from bottom to top. While looping the iteration is substituted with the lowest number in the array and this continues all the way to the end.
As you can see I'm refactoring to use stride. Unfortunately var lowest = firstIndex is giving me some troubles.
I should be able to complete this function using stride right? I believe I should be using stride: to instead of stride: through. Thanks to Tim for that tip.
func selOrganize(myList: Array<Int>) -> Array<Int> { 1
var extract = myList
for firstIndex in 0..<extract.count {
var lowest = firstIndex
for var secondIndex = firstIndex + 1; secondIndex < extract.count; secondIndex++ {
if extract[lowest] > extract[secondIndex] {
lowest = secondIndex
}
}
if firstIndex != lowest {
swap(&extract[firstIndex], &extract[lowest])
}
}
return extract
}
Updated syntax
func selOrganize(myList: Array<Int>) -> Array<Int> {
var extract = myList
// var lowest = firstIndex
// Do I need 'key'? Should I declare 'lowest' as a variable here?
// If I do use it here I get a "'lowest' is unmutable because it's a let" error
for (firstIndex, key) in extract.enumerate() {
// < > stride uses 'to' and <= >= stride uses through
for secondIndex in (firstIndex).stride(to: 0, by: +1) {
if extract[lowest] > extract[secondIndex] {
lowest = secondIndex
}
}
if firstIndex != lowest {
swap(&extract[firstIndex], &extract[lowest])
}
}
return extract
}

I got it to work like this:
func selOrganize(myList: Array<Int>) -> Array<Int> {
var extract = myList
// Accessing indices is simpler than calling enumerate, and
// the function only needs access to the indices, not the
// values of the enumeration:
for firstIndex in extract.indices {
// lowest needs to be defined inside this loop if you
// are going to initialize it using firstIndex
// because firstIndex isn't defined outside the loop.
var lowest = firstIndex
// You need to stride from the firstIndex to the end of the
// array, so the call to stride should look like this:
for secondIndex in firstIndex.stride(to: extract.count, by: 1) {
if extract[lowest] > extract[secondIndex] {
lowest = secondIndex
}
}
if firstIndex != lowest {
swap(&extract[firstIndex], &extract[lowest])
}
}
return extract
}

Stride is not needed, you can do that with standard for i in start..<end syntax
func selOrganize(myList: Array<Int>) -> Array<Int> {
var extract = myList
for firstIndex in 0..<extract.count {
var lowest = firstIndex
for secondIndex in (firstIndex + 1)..<extract.count {
if extract[lowest] > extract[secondIndex] {
lowest = secondIndex
}
}
if firstIndex != lowest {
swap(&extract[firstIndex], &extract[lowest])
}
}
return extract
}
But actually you can do the same in one line
let sortedList = myList.sort{$0 < $1}

Related

Finding indices of array elements that add up to a target number. What would be a way to optimize my solution?

I'm practicing this problem
Given an array of integers nums and an integer target, return indices
of the two numbers such that they add up to target.
You may assume that each input would have exactly one solution, and
you may not use the same element twice.
You can return the answer in any order.
and came up with
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var indices = [Int]()
for (firstIndex, firstNum) in nums.enumerated() {
for (secondIndex, secondNum) in nums.enumerated() {
if firstNum + secondNum == target && firstIndex != secondIndex {
indices = [firstIndex, secondIndex]
}
}
}
return indices
}
}
However, it has quadratic time complexity because of the nested for-in loops. What would be a good way to optimize this to run in linear time?
Here's an idea that results in a O(n) time ans space solution.
Have a hashtable that maps elements to their indices.
As you iterate through the input array check whether target - element is in the hashtable already. If so, return the indices of the current element and target - element in the hashtable.
If not, add current element as key and its index as value to the hashtable.
Using #user1984 comment your solution should look like this:
class Solution {
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var indices = [Int]()
var dictionary: [Int: Int] = [:]
for (index, num) in nums.enumerated()
{
let diff = target - num
if let index2 = dictionary[diff] {
return [index2, index]
}
else {
dictionary[num] = index
}
}
return []
}
}
There are several approaches (depending on your requirements and time/space constraints)
final class Solution {
// Time Complexity: O(n * (n - 1) / 2) = O(n^2)
// Auxiliary Space: O(1)
func twoSum1(_ nums: [Int], _ target: Int) -> [Int] {
for firstIndex in nums.indices {
for secondIndex in (firstIndex + 1)..<nums.count {
if nums[firstIndex] + nums[secondIndex] == target {
return [firstIndex, secondIndex]
}
}
}
return []
}
// Time Complexity: O(n log n).
// Auxiliary Space: O(n). Can be O(1) if do in-place sort
func twoSum2(_ nums: [Int], _ target: Int) -> [Int] {
let sorted = nums.sorted()
var left = 0
var right = nums.count - 1
while left < right {
if sorted[left] + sorted[right] == target {
return [left, right]
} else if sorted[left] + sorted[right] < target {
left += 1
} else {
right -= 1
}
}
return []
}
// Time Complexity: O(n). (Amortized)
// Auxiliary Space: O(n).
func twoSum3(_ nums: [Int], _ target: Int) -> [Int] {
var differences = [Int: Int]()
for (index, element) in nums.enumerated() {
let difference = target - element
if let dIndex = differences[difference] {
return [index, dIndex]
}
differences[element] = index
}
return []
}
static func test() {
// Given
let nums = [1, 5, 4, 3, 7, 9, -3]
let target = 7
let solution = Solution()
let expectedResult = [2, 3]
// When
let result1 = solution.twoSum1(nums, target)
let result2 = solution.twoSum2(nums, target)
let result3 = solution.twoSum3(nums, target)
// Then
assert(Set(result1) == Set(expectedResult))
assert(Set(result2) == Set(expectedResult))
assert(Set(result3) == Set(expectedResult))
}
}

How to add values of two arrays that are different sizes in length?

If I have two int arrays such as
var array1 = [1,2,3]
var array2 = [1,2,3,5]
I'd like to be able to add the first element of the first array with the first element of the second array, and so on. However if an array has a different length than the other I'd like to keep the element that was not added in the return array. For this example my return array would be [2,4,6,5].
I tried using zip(array1,array2).map(+) but it would exclude the 5 from array2.
After adding the elements at the index positions which are common to both arrays (what you already did with zip and map) just append the remaining elements from both arrays (using append(contentsOf:) and dropFirst):
let array1 = [1, 2, 3]
let array2 = [1, 2, 3, 5]
var combined = zip(array1, array2).map(+)
let commonCount = combined.count
combined.append(contentsOf: array1.dropFirst(commonCount))
combined.append(contentsOf: array2.dropFirst(commonCount))
print(combined) // [2, 4, 6, 5]
AnySequence(zip: (1...3, [1, 2, 3, 5])).map {
Optional($0).map(+) ?? firstNonNil($0)!
}
public extension AnySequence {
/// Like `zip`, but with `nil` elements for the shorter sequence after it is exhausted.
init<Sequence0: Sequence, Sequence1: Sequence>(
zip zipped: (Sequence0, Sequence1)
) where Element == (Sequence0.Element?, Sequence1.Element?) {
self.init(
sequence(
state: (zipped.0.makeIterator(), zipped.1.makeIterator())
) { iterators in
((iterators.0.next(), iterators.1.next()) as Optional)
.filter { $0 != nil || $1 != nil }
}
)
}
}
public extension Optional {
/// Exchange two optionals for a single optional tuple.
/// - Returns: `nil` if either tuple element is `nil`.
init<Wrapped0, Wrapped1>(_ optionals: (Wrapped0?, Wrapped1?))
where Wrapped == (Wrapped0, Wrapped1) {
switch optionals {
case let (wrapped0?, wrapped1?):
self = (wrapped0, wrapped1)
default:
self = nil
}
}
/// Transform `.some` into `.none`, if a condition fails.
/// - Parameters:
/// - isSome: The condition that will result in `nil`, when evaluated to `false`.
func filter(_ isSome: (Wrapped) throws -> Bool) rethrows -> Self {
try flatMap { try isSome($0) ? $0 : nil }
}
}
public func firstNonNil<Element>(_ tuple: (Element?, Element?)) -> Element? {
switch tuple {
case (let _0?, _):
return _0
case (nil, let _1?):
return _1
case (nil, nil):
return nil
}
}
func combine2Arrays(array1:[Int], array2:[Int]) -> [Int] {
var finalArray:[Int] = []
let maxSize = max(array1.count, array2.count)
for i in 0..<maxSize {
let valToAdd1 = (array1.count > i ? array1[i] : 0)
let valToAdd2 = (array2.count > i ? array2[i] : 0)
let finalVal = valToAdd1 + valToAdd2
finalArray.append(finalVal)
}
return finalArray
}
print(combine2Arrays(array1: [1,2,3], array2: [1,2,3,5]))
OR
func combine2Arrays(array1:[Int], array2:[Int]) -> [Int] {
var finalArray:[Int] = zip(array1,array2).map(+)
let largerArray = array1.count > array2.count ? array1 : array2
let smallerArray = array1.count > array2.count ? array2 : array1
let min = smallerArray.count
let max = largerArray.count
for i in min..<max {
finalArray.append(largerArray[i])
}
return finalArray
}
print(combine2Arrays(array1: [1,2,3], array2: [1,2,3,5]))
You can fill your smaller array with zeroes, then use zip. inout means that arrays are mutable, or you can make the copy of function parameters inside the function to make them mutable.
private func combineArrays(array1: inout [Int], array2: inout [Int]) -> [Int] {
let maxSize = max(array1.count, array2.count)
if (array1.count > array2.count) {
array2.append(contentsOf: [Int](repeating: 0, count: maxSize - array2.count))
} else if (array2.count > array1.count) {
array1.append(contentsOf: [Int](repeating: 0, count: maxSize - array1.count))
}
return zip(array1, array2).map(+)
}
//javaScript
var array1 = [1,2,3,4,5];
var array2 = [9,7,8,6,5,6,7];
let a= array1.length;
let b = array2.length;
var array3 = [];
let c = a>b?a:b;
for(let i=0; i<c; i++){
if(i < a && i < b){
array3.push(array1[i] + array2[i]);
} else if(i >= a){
array3.push(array2[i])
} else{
array3.push(array1[i])
}
}
console.log(array3)

CodingBat string_bits problem solved using swit for loop

Question:
Given a string, return a new string made of every other char starting with the first, so "Hello" yields "Hlo".
string_bits('Hello') → 'Hlo'
string_bits('Hi') → 'H'
string_bits('Heeololeo') → 'Hello'
Solution:
func string_bits(userString: String) ->String{
var myString = ""
for(i, v) in userString.enumerated(){
if i % 2 == 0{
myString.append(v)
}
}
return myString
}
Output: Hello
Now my question:
Is there any I can iterate my index any way in swift like object-c, c, or other programming languages does. For instance:
result = ""
# On each iteration, add the substring of the chars 0..i
for i in range(len(str)):
result = result + str[:i+1]
return result
str[:i+1]
Here, I am adding +1 with the current index and getting the index value. How can I do this in swift.
extension Collection {
func everyNthIndex(n: Int) -> UnfoldSequence<Index,Index> {
sequence(state: startIndex) { index in
guard index < endIndex else { return nil }
defer { index = self.index(index, offsetBy: n, limitedBy: endIndex) ?? endIndex }
return index
}
}
}
let alphabet = "abcdefghijklmnopqrstuvwxyz"
for evenIndex in alphabet.everyNthIndex(n: 2) {
print("evenIndex", evenIndex, "char:", alphabet[evenIndex])
}
for oddIndex in alphabet.dropFirst().everyNthIndex(n: 2) {
print("oddIndex", oddIndex, "char:", alphabet[oddIndex])
}
regular approach using while loop:
var index = alphabet.startIndex
while index < alphabet.endIndex {
defer { index = alphabet.index(index, offsetBy: 1) }
print(alphabet[index])
print(index)
}
or enumerating the string indices:
func string_bits(userString: String) -> String {
var myString = ""
for (offset,index) in userString.indices.enumerated() {
if offset.isMultiple(of: 2) {
myString.append(userString[index])
}
}
return myString
}

matrix Sort&Transpose swift4

I'm given a two dimensional array of integers as parameter and I should take it and sort. But sorting should be done manually. After sorting need should make a transpose of the sorted array and return the transposed one.
Input:[[3, 7, 9],[8, 6, 2],[1, 5, 4]]
Return value:[[1, 4, 7],[2, 5, 8],[3, 6, 9]]
func sortAndTranspose(matrix: [[Int]]) -> [[Int]] {
var isSwapped = true
while isSwapped == true {
isSwapped = false
for index in 1..<matrix.count {
if matrix[index] < matrix[index - 1] {
}
}
}
}
Here is my solution. I used flatMap to convert the matrix into an array, then I sorted the array using code I found in this answer. Once this was done I divided the array into a matrix
Updated version Make us of swapAt and support more than square formats. Thanks to #Rob for helping out.
func sortAndTranspose(matrix: [[Int]]) -> [[Int]] {
var array = matrix.flatMap({ $0 }) //create single row array
//manual sorting
for i in stride(from: array.count-1, to: 0, by: -1) {
for j in 1...i {
if array[j-1] > array[j] {
array.swapAt(j, j - 1)
}
}
}
//transpose sorted array back into 2D array
var result = [[Int]]()
let count = matrix[0].count
for i in 0..<array.count {
if (i < count) {
result.append([array[i]])
} else {
result[i % count].append(array[i])
}
}
Original answer
func sortAndTranspose(matrix: [[Int]]) -> [[Int]] {
var array = matrix.flatMap({ $0 }) //create single row array
//manual sorting
for i in stride(from: array.count-1, to: 0, by: -1) {
for j in 1...i {
if array[j-1] > array[j] {
let tmp = array[j-1]
array[j-1] = array[j]
array[j] = tmp
}
}
}
//transpose sorted array back into 2D array
var result = [[Int]]()
let count = matrix.count
for i in 0..<array.count {
if (i < count) {
result.append([array[i]])
} else {
result[i % count].append(array[i])
}
}

cannot assign through subscript in swift

I am trying to implement common alghorithm in Swift.
Even though I did not define numbers as a let variable, but I am getting following error:
cannot assign through subscript: 'numbers' is a 'let' constant
numbers[i] = maxNumber
My Implementation is as follows:
func InsertionSort (numbers : [Int]) -> [Int]
{
var maxNumber = 0
var j = 0
var size = numbers.count-1
for (i,number) in numbers.enumerated()
{
j = i + 1
for index in j...size
{
if numbers[index] > number
{
maxNumber = numbers[index]
numbers[index] = numbers[i]
// error is thrown in the following line
numbers[i] = maxNumber
}
}
}
return numbers
}
Parameters are immutable by default. To make a parameter mutable, you need to add an inout modifier.
However, seeing that your method returns an array, you probably don't want the parameter to be modified as well. You should instead make a copy of the parameter, modify that, and return the copy:
func InsertionSort (numbers : [Int]) -> [Int]
{
var maxNumber = 0
var j = 0
let size = numbers.count-1
var numbersCopy = numbers // <------ note this line
for (i,number) in numbers.enumerated()
{
j = i + 1
for index in j...size
{
if numbers[index] > number
{
maxNumber = numbers[index]
// note how I modified the copy here
numbersCopy[index] = numbers[i]
numbersCopy[i] = maxNumber
}
}
}
return numbersCopy
}