i want to use arc4random but produced Numbers are must different each other.
How do i do this example?
How about this:
let desired = 20
var randomSet: Set<Int> = [] //Sets guarantee uniqueness
var array: [Int] = [] //Use arrays to guarantee the order
while array.count < desired {
let random = Int(arc4random())
if !randomSet.contains(random) {
array.append(random)
randomSet.insert(random)
}
}
Or, using LeoDaubus' suggestion:
while array.count < desired {
let random = Int(arc4random())
if randomSet.insert(random).inserted {
array.append(random)
}
}
You can use Set to easily achieve this:
var randomSet: Set<Int> = [] //Sets guarantee uniqueness
var array: [Int] = [] //Use arrays to guarantee the order
while randomSet.count < 2 {
randomSet.insert(Int(arc4random())) //Whatever random number generator you use
}
for number in randomSet {
array.append(number)
}
//Now you can use the array for your operations
You can use a set to check if the random number was inserted appending the member after checking if it was inserted:
var set: Set<Int> = []
var randomElements: [Int] = []
let numberOfElements = 10
while set.count < numberOfElements {
let random = Int(arc4random_uniform(10)) // 0...9
set.insert(random).inserted ? randomElements.append(random) : ()
}
print(randomElements) // "[5, 2, 8, 0, 7, 1, 4, 3, 6, 9]\n"
Related
I'm getting an Xcode error
Global function 'zip' requires that 'String.Element' (aka 'Character') conform to 'Sequence'
on array[i] = zip(array[i], arrayOfZeros)
func expandedForm(_ num: Int) -> String {
let lenght = String(num).count
var array = Array(String(num))
var i = 0
while array.count > i {
let numberOfZeros = array.count - 1 - i
let arrayOfZeros = Array(repeating: "0", count: numberOfZeros)
let string = array[i]
array[i] = zip(array[i], arrayOfZeros)
i += 1
}
return ""
}
I'm trying to merge two array of strings, but I think they are not the same type. Need some help on this.
func expandedForm(_ num: Int) -> String {
let lenght = String(num).count
var array = Array(String(num))
var i = 0
while array.count > i {
let numberOfZeros = array.count - 1 - i
let arrayOfZeros = Array(repeating: "0", count: numberOfZeros)
let string = array[i]
array[i] = zip(array[i], arrayOfZeros)
i += 1
}
return ""
}
You have some issues.
var array = Array(String(num)), if you pass your cursor on array, it's a [String.Element], ie a [Character], an array a Character.
So let string = array[i], that's misleading, because array[i] is a Character, not a String.
zip(_:_:) awaits for two sequences (~array), and you give as first parameter a Character.
Possible solutions:
Make array, a real array of String:
var array = Array(String(num)).map { String($0) }
And then:
array[i] = array[i] + arrayOfZeros.joined()
Or create a new variable var output that will be an array of String:
var output: [String] = []
And populate it:
output.append(String(array[i] + arrayOfZeros.joined())
I am trying to find an efficient way to solve the find a missing number from an array. I implemented the following way it's O(n). Please write any codes that efficiently solves this, just for learning purpose.
func findMissingNo(arrA: [Int]) -> [Int] {
let firstIndex = arrA.first ?? 0
let lastIndex = arrA.last ?? 0
let rslt = Array(firstIndex...lastIndex)
let missingNoArray = rslt.filter{ !arrA.contains($0)}
return missingNoArray
}
findMissingNo(arrA: [11,12,14,15,16,18]) // Prints [13, 17] by looping 9 times
Quickly written and tested (in terms of times performances against your code, but not in term of possible edges cases/mistakes, for instance, if array is 0...10, it won't work, but I'll let you work on the edges cases, since I focused mainly on the main cases, cases which might be covered during an edit and the end of the question)
Your current code:
func findMissingNo(arrA: [Int]) -> [Int] {
let firstIndex = arrA.first ?? 0
let lastIndex = arrA.last ?? 0
let rslt = Array(firstIndex...lastIndex)
let missingNoArray = rslt.filter{ !arrA.contains($0)}
return missingNoArray
}
let numberArray = [11,12,14,15,18]
let missing1 = findMissingNo(arrA: numberArray)
print("Missing1: \(missing1)")
My attempt:
func findMissingNo2(arrA: [Int]) -> [Int] {
var missingNumbers: [Int] = []
guard arrA.count > 2 else { return missingNumbers }
for i in 0...arrA.count-2 {
var current = arrA[i]
let next = arrA[i+1]
if next != current + 1 {
current += 1
while current != next {
missingNumbers.append(current)
current += 1
}
}
}
return missingNumbers
}
let missing2 = findMissingNo2(arrA: numberArray)
print("Missing1: \(missing2)")
Creating a big batch:
var array = Array(0...1000)
for _ in 0...10 {
if let index = array.indices.randomElement() {
let value = array.remove(at: index)
print("removed: \(value)") //To check just in case that's the good value returned by the methods
}
}
Testing:
let date1 = Date()
for _ in 0...100 {
let missing = findMissingNo(arrA: array)
print(missing)
}
print(Date().timeIntervalSince(date1)) //18.617565035820007
let date2 = Date()
for _ in 0...100 {
let missing = findMissingNo2(arrA: array)
print(missing)
}
print(Date().timeIntervalSince(date2)) //0.09566605091094971
print("---End")
print("")
For the time, I got: 18.857954025268555 vs 0.09159696102142334, a big factor difference (~200 times).
Why is there such a big difference?
Because of
let missingNoArray = rslt.filter{ !arrA.contains($0)}
It means:
for each number in result, check if arrayA contains that number.
->
for each number in result, for each number in arrayA (with a stop condition, so it's not a full iteration, but "almost" in term of complexity) check if there is a match...
Here there is a "double" (which is in fact not double, but n?) iteration that you missed.
I tested first with bigger value (array from "0 to 100000"), but it was taking too much time, with that "low number of values", the difference can already be seen.
Instead, you could use a Set:
let missingNoArray = Array(Set(rslt).subtracting(Set(arrA))).sorted()
It's faster than you method in my tests, (double my solution (0.21 ~ 0.22) in time performances), but still much faster than yours.
I added the sorted(), which may or may not be important in your solution, but will add time consumption since Set aren't ordered.
For the edges cases (ie: [3], [3, 4], [3, 8])
guard arrA.count > 2 else { return missingNumbers }
==>
guard !arrA.isEmpty else { return [] }
guard arrA.count > 2 else {
if arrA[0] + 1 >= arrA[1] {
return []
} else {
return Array((arrA[0] + 1)...arrA[1]).dropLast() //Because last will be arrA[1] which is present)
}
}
My Task:
I need to divide the Array into several Arrays of Arrays with the following properties:
every subarray is a range of continuous integer. As example [1,2,3,4,5] will be [[1,5]].
When there are no contiguous integer create a new subarray. As example [1,2,4,5] will be [[1,2], [4,5]]
Example:
If I have this Array of Integers - [0, 1, 5, 6, 3, 7]
Expected Result - [[0, 1], [3], [5, 7]]
I already tried this:
let array: [Int] = [0, 1, 3, 4, 5, 6, 7]
var group: [[Int]] = []
var temp: [Int] = [Int]()
for (index, element) in array.enumerated() {
if index + 1 < array.count {
let nextElement = array[index + 1]
let step = nextElement - element
// temp.append(element)
if(step) == 1 { // Until it's in range
temp.append(element)
} else { // One-by-one
temp.append(element)
group.append(temp)
temp = [Int]()
group.append([nextElement])
}
} else {
print(index)
}
}
print(group)
From my code, I get this result - [[0, 1], [3]]
There is an API, IndexSet:
It's not clear what you want, your examples are ambiguous.
If you want an array of ranges
let indexSet = IndexSet(array)
let rangeView = indexSet.rangeView
let group = rangeView.map { $0.indices.startIndex..<$0.indices.endIndex }
If you want a grouped array by ranges
let indexSet = IndexSet(array)
let rangeView = indexSet.rangeView
let group = rangeView.map { Array($0.indices) }
This is the best approach I found:
let array: [Int] = [0, 1, 5, 6, 3, 7].sorted();
var group: [[Int]] = []
var temp: [Int] = [Int]()
var lastElement: Int = -1;
for (index, element) in array.enumerated() {
if lastElement == -1 {
temp.append(element);
}
else {
if element - lastElement == 1 {
temp.append(element);
}
else {
group.append(temp);
temp = [Int]();
temp.append(element);
}
}
lastElement = element;
}
if temp.count > 0 {
group.append(temp);
}
print(group)
Here is my solution. Rather than manually managing indexes, I use two iterators. One which advances along denoting the "start" of runs, and one which races ahead to find the "ends" of runs.
I've gentrified my code to work over any Sequence (not just Array), and any Strideable type (any type that defines distance(to:), not necessarily just Int).
extension Sequence where Element: Strideable {
func splitConsequtiveRuns() -> [[Element]] {
var runs = [[Element]]()
var runStartIterator = self.makeIterator()
while let startElement = runStartIterator.next() {
var runEndIterator = runStartIterator
var prevElement = startElement
var run = [startElement]
while let nextElement = runEndIterator.next(),
prevElement.distance(to: nextElement) == 1 {
_ = runStartIterator.next() // advance the "start" iterator, to keep pace
prevElement = nextElement // update this, for use in then next loop's comparison
run.append(nextElement)
}
runs.append(run)
}
return runs
}
}
let array: [Int] = [0...3, 8...8, 10...15].flatMap { $0 }
print(array.splitConsequtiveRuns()) // => [[0, 1, 2, 3], [8], [10, 11, 12, 13, 14, 15]]
I am quite new to Swift 3 and to programming languages in general. I have the following arrays inside an array and a variable income:
let testArray: [[Double]] = [
[0,0],
[1000,20.5],
[3000,21],
[4000,22.5],
]
var income: Double = 3500
What I want to do is something similar to the VLOOKUP function in Excel: I want to find in the first column of the arrays (i.e. 0, 1000, 3000, 4000) a number which is equal or immediately smaller than my variable. In this case, as income = 3500, the program should return 3000. I tried using filter() but I don't know how to work with the arrays inside the array. Any help appreciated.
You can proceed as follows.
Get the first column of the array:
let firstColumn = testArray.map { $0[0] }
print(firstColumn) // [0.0, 1000.0, 3000.0, 4000.0]
Restrict to those elements which are less than or equal to the
given amount:
let filtered = firstColumn.filter { $0 <= income }
print(filtered) // [0.0, 1000.0, 3000.0]
Get the maximal element of the filtered array. If the elements are
sorted in increasing order then you can use last instead of max():
let result = filtered.max()!
// Or: let result = filtered.last!
print(result) // 3000.0
Putting it all together:
let result = testArray.map { $0[0] }.filter { $0 <= income }.max()!
print(result) // 3000.0
A possible optimization is to combine map and filter into
flatMap:
let result = testArray.flatMap { $0[0] <= income ? $0[0] : nil }.max()!
print(result) // 3000.0
This code assumes that there is at least one matching element,
otherwise last! or max()! would crash. If that is not guaranteed:
if let result = testArray.flatMap( { $0[0] <= income ? $0[0] : nil }).max() {
print(result) // 3000.0
} else {
print("no result")
}
Or provide a default value (0.0 in this example):
let result = testArray.flatMap( { $0[0] <= income ? $0[0] : nil }).max() ?? 0.0
print(result) // 3000.0
Something like this:
let testArray: [[Double]] = [
[0,0],
[1000,20.5],
[3000,21],
[3500,22.5],
[3300,21],
]
let income: Double = 3500
var closest = testArray[0][0]
var closestDif = closest - income
for innerArray in testArray {
let value = innerArray[0]
let thisDif = value - income
guard thisDif <= 0 else {
continue
}
if closestDif < thisDif {
closestDif = thisDif
closest = value
guard closestDif != 0 else {
break
}
}
}
print(closest)
I have a array that looks like this:
var myArray = ["1one", "1two", "1three", "1four", "1five", "1six"]
And to get random, I use this:
var originalNames = [String]()
func getRandomName() -> String {
if (names.count == 0) {
names = originalNames
}
let randomNumber = Int(arc4random_uniform(UInt32(names.count)))
return names.removeAtIndex(randomNumber)
}
And I use it like this:
self.randomLabel.text = getRandomName()
As you can see, the array contains six different strings. The code that I am currently using, will return add the strings inside the array at random, but I only want to return the first 3 strings randomly. How can I do this?
You can try using
var originalNames = [String]()
func getRandomName() -> String {
if (names.count == 0) {
names = originalNames
}
let randomNumber = Int(arc4random_uniform(3))
return names[randomNumber]
}
so let randomNumber = Int(arc4random_uniform(3)) this will return random Int value upto 3.
var myArray = ["1one", "1two", "1three", "1four", "1five", "1six"]
var result:[String] = []
while result.count < 3 {
let randomNumber = Int(arc4random_uniform(UInt32(myArray.count)))
result.append(myArray.removeAtIndex(randomNumber))
}
print(result) // "["1two", "1one", "1three"]\n"
if you don't want to modify the original array just make a copy of it
let myArray = ["1one", "1two", "1three", "1four", "1five", "1six"]
var inputNames = myArray
var result:[String] = []
while result.count < 3 {
result.append(inputNames.removeAtIndex(Int(arc4random_uniform(UInt32(inputNames.count)))))
}
print(result) // "["1six", "1two", "1one"]\n"