I am currently completing a challenge on hacker rank called compare the triplets (https://www.hackerrank.com/challenges/compare-the-triplets/problem), and I was just wondering if using too many IF statements is considered bad programming practice? What are the alternatives other than using switch statements. Please see my code solution below :
import Foundation
func compareTriplets(a: [Int], b: [Int]) -> [Int] {
var compareArray = [0,0]
if a[0] == b[0]{
compareArray[0] = compareArray[0]
}
if a[0] < b[0]{
compareArray[0] = compareArray[0] + 1
}
if a[1] < b[1] {
compareArray[0] = compareArray[0] + 1
}
if a[2] < b[2] {
compareArray[0] = compareArray[0] + 1
}
if a[0] > b[0]{
compareArray[1] = compareArray[1] + 1
}
if a[1] > b[1] {
compareArray[1] = compareArray[1] + 1
}
if a[2] > b[2] {
compareArray[1] = compareArray[1] + 1
}
return compareArray
}
print(compareTriplets(a: [17,28,30], b: [99,28,8]))
This will expand a lot if you will have more and more elements in arrays you send.
Why not try something like
func compareTriplets(a: [Int], b: [Int]) -> [Int] {
var compareArray = [0,0]
if a.count != b.count {
return compareArray
}
for index in 0..<(a.count) {
if a[index] > b[index] {
compareArray[0] += 1
}
else if a[index] < b[index] {
compareArray[1] += 1
}
}
return compareArray
}
Of course, if array lengths can differ then you can take min or go to minimum array length.
Related
I'm writing a function thats supposed to loop though a 2D array diagonally(top left to bottom right). However, the code does not add to the outer while loop(i), it keeps it at 0. arr is 9X9
var i = 0
var j = 0
while(i < arr.count-1){
while (j < arr.count-1) {
print("i = \(i) --- j = \(j)")
if(i == j){
sumDiagonalLeft += arr[j][i]
print(sumDiagonalLeft)
if(arr[j][i] == 1){
informationUsed += 1
arr[i][j] = 2
}
}
j += 1
}
i += 1
}
Thank you for your time :)
try this,
var array:[[Int]] = []
array.append([1,2,3,4,5,6,7,8,9])
....
array.append([1,2,3,4,5,6,7,8,9])
for (index, element) in array.enumerated(){
for (innerIndex,innerElement) in element.enumerated(){
print(innerElement) // you can do your logics here
}
}
I hope you guys can check. when I use 5 as x it should be showing me -0.17749282815107623 but it returns -0.2792375. I couldn't where I have been doing the mistake.
var evenNumbers = [Int]()
for i in 2...10 {
if i % 2 == 0 {
evenNumbers.append(i)
}
}
func power(val: Float, power: Int)->Float{
var c:Float = 1
for i in 1...power {
c *= val
}
return c
}
func bessel(x: Float)->Float{
var j0:Float = 0
var counter = 1
var lastDetermVal:Float = 1
for eNumber in evenNumbers {
print(lastDetermVal)
if counter == 1 {
lastDetermVal *= power(val: Float(eNumber), power: 2)
j0 += (power(val: x, power: eNumber))/lastDetermVal
counter = -1
}else if counter == -1{
lastDetermVal *= power(val: Float(eNumber), power: 2)
j0 -= (power(val: x, power: eNumber))/lastDetermVal
counter = 1
}
}
return 1-j0
}
bessel(x: 5)
Function 1:
Your mistake seems to be that you didn't have enough even numbers.
var evenNumbers = [Int]()
for i in 2...10 {
if i % 2 == 0 {
evenNumbers.append(i)
}
}
After the above is run, evenNumbers will be populated with [2,4,6,8,10]. But to evaluate 10 terms, you need even numbers up to 18 or 20, depending on whether you count 1 as a "term". Therefore, you should loop up to 18 or 20:
var evenNumbers = [Int]()
for i in 2...18 { // I think the 1 at the beginning should count as a "term"
if i % 2 == 0 {
evenNumbers.append(i)
}
}
Alternatively, you can create this array like this:
let evenNumbers = (1..<10).map { $0 * 2 }
This means "for each number between 1 (inclusive) and 10 (exclusive), multiply each by 2".
Now your solution will give you an answer of -0.1776034.
Here's my (rather slow) solution:
func productOfFirstNEvenNumbers(_ n: Int) -> Float {
if n == 0 {
return 1
}
let firstNEvenNumbers = (1...n).map { Float($0) * 2.0 }
// ".reduce(1.0, *)" means "multiply everything"
return firstNEvenNumbers.reduce(1.0, *)
}
func nthTerm(_ n: Int, x: Float) -> Float {
let numerator = pow(x, Float(n) * 2)
// yes, this does recalculate the product of even numbers every time...
let product = productOfFirstNEvenNumbers(n)
let denominator = product * product
return numerator / (denominator) * pow(-1, Float(n))
}
func bessel10Terms(x: Float) -> Float {
// for each number n in the range 0..<10, get the nth term, add them together
(0..<10).map { nthTerm($0, x: x) }.reduce(0, +)
}
print(bessel10Terms(x: 5))
You code is a bit unreadable, however, I have written a simple solution so try to compare your intermediate results:
var terms: [Float] = []
let x: Float = 5
for index in 0 ..< 10 {
guard index > 0 else {
terms.append(1)
continue
}
// calculate only the multiplier for the previous term
// - (minus) to change the sign
// x * x to multiply nominator
// (Float(index * 2) * Float(index * 2) to multiply denominator
let termFactor = -(x * x) / (Float(index * 2) * Float(index * 2))
terms.append(terms[index - 1] * termFactor)
}
print(terms)
// sum the terms
let result = terms.reduce(0, +)
print(result)
One of the errors I see is the fact that you are actually calculating only 5 terms, not 10 (you iterate 1 to 10, but only even numbers).
Here is my code.
import UIKit
var str = "Hello, playground"
//There are two sorted arrays nums1 and nums2 of size m and n respectively.
//Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
//Example 1:
//nums1 = [1, 3]
//nums2 = [2]
//
//The median is 2.0
//Example 2:
//nums1 = [1, 2]
//nums2 = [3, 4]
//
//The median is (2 + 3)/2 = 2.5
var num1 = [1,2,2,5]
var num2 = [2,3,9,9]
class Solution {
func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
var A = nums1
var B = nums2
var m = nums1.count
var n = nums2.count
var max_of_left : Int = 0
var min_of_right = 0
if n < m {
var temp : [Int]
var tempt : Int
temp = nums1
tempt = m
A = nums2
B = temp
m = n
n = tempt
}
if n == 0{
fatalError("Arrays must be fulfilled")
}
var imin = 0
var imax = m
let half_len = Int((m+n+1)/2)
while imin <= imax {
let i = Int((imin + imax) / 2)
let j = half_len - i
if i > 0 && A[i-1] > B[j]{
imax = i - 1
}
else if i < m && A[i] < B[j-1]{
imin = i + 1
}
else
{
if i == 0{
max_of_left = B[j-1]
}
else if j == 0{
max_of_left = A[i-1]
}
else
{
max_of_left = max(A[i-1], B[j-1])
}
if m+n % 2 == 1{
return Double(max_of_left)
}
if i==m{
min_of_right = B[j]
}
else if j == n{
min_of_right = A[i]
}
else{
min_of_right = min(A[i], B[j])
//editor indicates error here
}
return Double((Double(max_of_left+min_of_right) / 2.0))
}
}
}
}
var a = Solution()
print(a.findMedianSortedArrays(num1, num2))
error: day4_Median_of_Two_Sorted_Arrays.playground:86:13: error: missing return in a function expected to return 'Double'
Since I put my return out of if statement, I think it will be okay because it will stop while looping when it meets return.
But editor says it's not.
I want to know why. Please explain me why.
Every code path through your findMedianSortedArrays() must return a Double.
So you need a return of a Double placed outside of your while loop. Even if you had every code path within the while loop have a return double, if imin > imax you wouldn't even enter the while loop, and so would need a return of a double outside it.
I fixed it by putting another return out of while loop.
//: Playground - noun: a place where people can play
import UIKit
var str = "Hello, playground"
//There are two sorted arrays nums1 and nums2 of size m and n respectively.
//Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
//Example 1:
//nums1 = [1, 3]
//nums2 = [2]
//
//The median is 2.0
//Example 2:
//nums1 = [1, 2]
//nums2 = [3, 4]
//
//The median is (2 + 3)/2 = 2.5
var num1 = [1,2,2,5]
var num2 = [2,3,9,9]
class Solution {
func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double {
var A = nums1
var B = nums2
var m = nums1.count
var n = nums2.count
var max_of_left : Int = 0
var min_of_right = 0
if n < m {
var temp : [Int]
var tempt : Int
temp = nums1
tempt = m
A = nums2
B = temp
m = n
n = tempt
}
if n == 0{
fatalError("Arrays must be fulfilled")
}
var imin = 0
var imax = m
let half_len = Int((m+n+1)/2)
while imin <= imax {
let i = Int((imin + imax) / 2)
let j = half_len - i
if i > 0 && A[i-1] > B[j]{
imax = i - 1
}
else if i < m && A[i] < B[j-1]{
imin = i + 1
}
else
{
if i == 0{
max_of_left = B[j-1]
}
else if j == 0{
max_of_left = A[i-1]
}
else
{
max_of_left = max(A[i-1], B[j-1])
}
if m+n % 2 == 1{
return Double(max_of_left)
}
if i==m{
min_of_right = B[j]
}
else if j == n{
min_of_right = A[i]
}
else{
min_of_right = min(A[i], B[j])
}
return Double((Double(max_of_left+min_of_right) / 2.0))
}
}
return Double((Double(max_of_left+min_of_right) / 2.0))
}
}
var a = Solution()
print(a.findMedianSortedArrays(num1, num2))
I have following line in my code:
for (i = 0, j = count - 1; i < count; j = i++)
Can anyone help to remove the two compiler warnings, that i++ will be removed in Swift 3.0 and C-style for statement is depreciated?
You could use this:
var j = count-1
for i in 0..<count {
defer { j = i } // This will keep the cycle "logic" all together, similarly to "j = i++"
// Cycle body
}
EDIT
As #t0rst noted, be careful using defer, since it will be executed no matter how its enclosing scope is exited, so it isn't a 100% replacement.
So while the standard for ( forInit ; forTest ; forNext ) { … } will not execute forNext in case of a break statement inside the cycle, a return or an exception, the defer will.
Read here for more
Alternatively, lets go crazy to avoid having to declare j as external to the loop scope!
Snippet 1
let count = 10
for (i, j) in [count-1..<count, 0..<count-1].flatten().enumerate() {
print(i, j)
}
/* 0 9
1 0
2 1
3 2
4 3
5 4
6 5
7 6
8 7
9 8 */
Snippet 2
for (i, j) in (-1..<count-1).map({ $0 < 0 ? count-1 : $0 }).enumerate() {
print(i, j)
}
Trying to win the prize for the craziest solution in this thread
Snippet 1
extension Int {
func j(count:Int) -> Int {
return (self + count - 1) % count
}
}
for i in 0..<count {
print(i, i.j(count))
}
Snippet 2
let count = 10
let iList = 0..<count
let jList = iList.map { ($0 + count - 1) % count }
zip(iList, jList).forEach { (i, j) in
print(i, j)
}
You could use a helper function to abstract away the wrapping of j as:
func go(count: Int, block: (Int, Int) -> ()) {
if count < 1 { return }
block(0, count - 1)
for i in 1 ..< count {
block(i, i - 1)
}
}
I have updated Xcode (7.3) and there are a lot of changes; C-like for expressions will be deprecated. For a simple example,
for var i = 0; i <= array.count - 1; i++
{
//something with array[i]
}
How do I write this clear and simple C-like for-loop to be compliant with the new changes?
for var i = 0, j = 1; i <= array.count - 2 && j <= array.count - 1; i++, j++
{
//something with array[i] and array[j]
}
Update.
One more variant
for var i = 0; i <= <array.count - 1; i++
{
for var j = i + 1; j <= array.count - 1; j++
{
//something with array[i] and array[j]
}
}
And more ...
for var i = 0, j = 1, g = 2; i <= array.count - 3 && j <= array.count - 2 && g <= array.count - 1; i++, j++, g++
{
//something with array[i] and array[j] and array[g]
}
Update2 After several suggestions for me while loop is preferable universal substitution for all cases more complicated than the simple example of C-like for-loop (suitable for for in expression). No need every time to search for new approach.
For instance: Instead of
for var i = 0; i <= <array.count - 1; i++
{
for var j = i + 1; j <= array.count - 1; j++
{
//something with array[i] and array[j]
}
}
I can use
var i = 0
while i < array.count
{
var j = i + 1
while j < array.count
{
//something with array[i] and array[j]
j += 1
}
i += 1
}
charl's (old) answer will crash. You want 0..<array.count:
for index in 0..<array.count {
// ...
}
If you want something like your i/j loop you can use stride and get i's successor:
for i in 0.stride(through: array.count, by: 1) {
let j = i.successor()
// ...
}
Just make sure to check i.successor() in case you go out of bounds.
for var i = 0; i <= array.count - 1; i++ {
//something with array[i]
}
Here you don't need the element index at all, so you can simply
enumerate the array elements:
for elem in array {
// Do something with elem ...
}
for var i = 0, j = 1; i <= array.count - 2 && j <= array.count - 1; i++, j++ {
//something with array[i] and array[j]
}
To iterate over pairs of adjacent elements, use zip()
and dropFirst():
for (x, y) in zip(array, array.dropFirst()) {
// Do something with x and y ...
print(x, y)
}
Output:
1 2
2 3
3 4
4 5
For other distances, use dropFirst(n):
for (x, y) in zip(array, array.dropFirst(3)) {
// Do something with x and y ...
print(x, y)
}
Output:
1 4
2 5
There are probably many solutions to do
for var i = 0; i <= <array.count - 1; i++ {
for var j = i + 1; j <= array.count - 1; j++ {
//something with array[i] and array[j]
}
}
without a C-style for-loop, here is one:
for (index, x) in array.enumerate() {
for y in array.dropFirst(index + 1) {
print(x, y)
}
}
If you want to do something with subsequent pairs there are many other ways to do it.
Something like this would work...
var previousItem = array.first
for index in 1..<array.count {
let currentItem = array[index]
// do something with current and previous items
previousItem = currentItem
}
for (i, j) in zip(array.dropLast(), array.dropFirst())
{
// something
}
What you're really doing here is enumerating two parallel sequences. So, create those sequences and use zip to turn them into a single sequence.
Do enumeration
let suits = ["♠︎", "♥︎", "♣︎", "♦︎"]
for (i, suite) in suits.enumerate() {
// ...
}
or to compare neighbors
import Foundation
let suits = ["♠︎", "♥︎", "♣︎", "♦︎"]
for (i, suite1) in suits.enumerate() {
let j = i.successor()
if j < suits.count {
let suite2 = suits[j]
// ...
}
}
or zipping and enumerating
let suits = ["♠︎", "♥︎", "♣︎", "♦︎"]
let combination = zip(suits, suits.dropFirst())
for (i, (s1,s2)) in combination.enumerate() {
print("\(i): \(s1) \(s2)")
}
result
0: ♠︎ ♥︎
1: ♥︎ ♣︎
2: ♣︎ ♦︎
Worst case, you can convert it to a while loop.
var i = 0
var j = 1
while i <= array.count -2 && j <= array.count - 1 {
// something
i += 1
j += 1
}
-- EDIT --
Because you said, "while loop is preferable universal substitution for all cases more complicated than the simple example of C-like for-loop"... I feel the need to expand on my answer. I don't want to be responsible for a bunch of bad code...
In most cases, there is a simple for-in loop that can handle the situation:
for item in array {
// do something with item
}
for (item1, item2) in zip(array, array[1 ..< array.count]) {
// do something with item1 and item2
}
for (index, item1) in array.enumerate() {
for item2 in array[index + 1 ..< array.count] {
// do soemthing with item1 and item2
}
}
For your last case, you might be justified using a for look, but that is an extremely rare edge case.
Don't litter your code with for loops.
to compare neighbouring elements from the same array you can use
let arr = [1,2,2,5,2,2,3,3]
arr.reduce(nil) { (i, j)->Int? in
if let i = i {
print(i,"==",j,"is",i == j)
}
return j
}
it prints
1 == 2 is false
2 == 2 is true
2 == 5 is false
5 == 2 is false
2 == 2 is true
2 == 3 is false
3 == 3 is true
more 'generic' approach without using subscript but separate generators
let arr1 = [1,2,3,4,5,6,7,8,9,0]
var g1 = arr1.generate()
var g2 = (arr1.dropFirst(5) as AnySequence).generate()
var g3 = (arr1.dropFirst(6) as AnySequence).generate()
while true {
if let a1 = g1.next(),
let a2 = g2.next(),
let a3 = g3.next() {
print(a1,a2,a3)
} else {
break
}
}
/* prints
1 6 7
2 7 8
3 8 9
4 9 0
*/