Swift Joining 2 Arrays in Specific Order - arrays

I wrote the following code in a playground and it works fine, but it seems a little messy. Is there a more concise way of writing this in Swift?
I want a string to look like the following:
1, 12, 2, 12, 3, 12, 4, 13, 5, 13, 6, 13, 7, 14, 8, 14
I will not know how many values in each array and the arrays may not be even multiples, but I will know the relationship of 3 array1 values for each array2 value
let array1 = [1,2,3,4,5,6,7,8] //sample 1st array
let array2 = [12,13,14] //sample 2nd array
let relationshipInterval = 3
let remainder = (array1.count % relationshipInterval)
let multiples = (array1.count - remainder)/relationshipInterval
var string = ""
var array1Start = 0
var array1End = relationshipInterval-1
var array2Value = 0
for _ in 1...multiples {
for array1value in array1[array1Start...array1End] {
string += "\(array1value), "
string += String(array2[array2Value])+", "
}
array1Start = array1End + 1
array1End = array1Start + relationshipInterval - 1
array2Value += 1
}
for array1value in array1[array1Start...array1Start+remainder-1] {
string += "\(array1value), "
string += String(array2[array2Value])+", "
}
print (string) //prints 1, 12, 2, 12, 3, 12, 4, 13, 5, 13, 6, 13, 7, 14, 8, 14

I'm not sure if this covers all of the use cases, but using zip, flatMap, and joined you do this in a single step!
let array1 = [1,2,3,4,5,6,7,8]
let array2 = [12, 13, 14]
let text = zip(array1, array2.flatMap({ [$0, $0, $0] }))
.flatMap({ [$0, $1] })
.map({ String($0) })
.joined(separator: ", ")
// text -> "1, 12, 2, 12, 3, 12, 4, 13, 5, 13, 6, 13, 7, 14, 8, 14"
Here's that one-liner broken into four steps so it's clearer what's happening at each stage:
// 1. create an array with each element in array2 is trippled:
let trippled = array2.flatMap({ item in
return [item, item, item]
})
// trippled -> [12, 12, 12, 13, 13, 13, 14, 14, 14]
// 2. zip array1 with the trippled array:
let zipped = zip(array1, trippled)
// zipped -> Zip2Sequence(_sequence1: [1, 2, 3, 4, 5, 6, 7, 8], _sequence2: [12, 12, 12, 13, 13, 13, 14, 14, 14])
// 3. flatten the zipped aray
let combined = zipped.flatMap({ leftItem, rightItem in
return [leftItem, rightItem]
})
// combined -> [1, 12, 2, 12, 3, 12, 4, 13, 5, 13, 6, 13, 7, 14, 8, 14]
// 4. tranform to a string
let text = combined.map({ item in
return "\(item)"
}).joined(separator: ", ")
// text -> "1, 12, 2, 12, 3, 12, 4, 13, 5, 13, 6, 13, 7, 14, 8, 14"

Related

How do I return a Random number every time in Math Random.?

I just have a question,
I have been building alexa skill. (the Concept is Randomize Positivity)
but somehow it keep returning the same sentence....
this is my code...
` for (var j = 0; j < index; j++){
var rand = Math.floor(Math.random() * index);
index -= 1;
var temp = indexList[index];
indexList[index] = indexList[rand];
indexList[rand] = temp;
}`// I also swap the words so It would sure not to return the same but somehow it happens..
and the index is about 15 strings for now...
my Question is how do I make it random as possible?
You're just trying to shuffle an array, right? See the Fisher-Yates shuffle. You're already almost doing the same thing.
I tried this and it worked fine.
var indexList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
var rand;
var temp;
for (let i = 0; i < indexList.length; i++) {
rand = Math.floor(Math.random() * (i + 1));
temp = indexList[i];
indexList[i] = indexList[rand];
indexList[rand] = temp;
console.log(indexList);
}
It printed the following, showing that it is shuffling the array more and more each step:
> Array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [3, 1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [4, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [4, 1, 5, 3, 2, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 1, 7, 8, 9, 10, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 8, 7, 1, 9, 10, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 8, 9, 1, 7, 10, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 8, 9, 1, 10, 7, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 8, 9, 1, 10, 7, 11, 12, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 8, 9, 1, 12, 7, 11, 10, 13, 14, 15]
> Array [4, 6, 5, 3, 2, 8, 9, 1, 12, 7, 11, 10, 13, 14, 15]
> Array [4, 6, 14, 3, 2, 8, 9, 1, 12, 7, 11, 10, 13, 5, 15]
> Array [4, 6, 15, 3, 2, 8, 9, 1, 12, 7, 11, 10, 13, 5, 14]

Swift using eratosthenes method to get prime numbers

I want to use eratosthenes method
to get prime numbers with swift. I create first function to return new array without those numbers that can be divided for specific multiplier, then create second function to create new array every time with new P multiplier. I wonder why its not work (look like it somehow pass old array, i dont know why). It should print new array of prime numbers at the end:
var simpleArr : [Int] = []
for i in 2...100 {
simpleArr.append(i)
}
func arrayEcludingDivingByP (p: Int, arrToCheck : [Int]) -> Array<Int>{
var tmp : [Int] = []
for (ob, index) in arrToCheck.enumerated() {
var isDividible : Bool = ob % p == 0 ? true : false
if (!isDividible){
tmp.append(ob)
}
}
return tmp
}
var p : Int = 2
func getSimpleNumbersArrayFromArray (p : Int, arrPassed : [Int]) -> Array <Int>{
var tmp : [Int] = []
var newArr = arrayEcludingDivingByP(p: p, arrToCheck: arrPassed)
if (newArr.isEmpty){
// No more p availible, just return tmp
} else {
let newP = p + 1
getSimpleNumbersArrayFromArray(p: newP, arrPassed: newArr)
tmp = newArr
print("tmp array? \(tmp)")
}
return tmp
}
getSimpleNumbersArrayFromArray(p: p, arrPassed: simpleArr)
In console it prints:
tmp array? [1]
tmp array? [1, 2]
tmp array? [1, 2, 3]
tmp array? [1, 2, 3, 4]
tmp array? [1, 2, 3, 4, 5]
tmp array? [1, 2, 3, 4, 5, 6]
tmp array? [1, 2, 3, 4, 5, 6, 7]
tmp array? [1, 2, 3, 4, 5, 6, 7, 8]
tmp array? [1, 2, 3, 4, 5, 6, 7, 9, 10, 11]
tmp array? [1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13]
tmp array? [1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17]
tmp array? [1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14, 16, 17, 18, 19, 21, 22, 23]
tmp array? [1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15, 17, 18, 19, 21, 22, 23, 25, 26, 27, 29, 30, 31]
tmp array? [1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23, 25, 26, 28, 29, 31, 32, 34, 35, 37, 38, 40, 41, 43, 44, 46, 47]
tmp array? [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97]
But it suppose to print final iteration with tmp filled with prime numbers. What did i wrong?
You are using newArr to represent the values in the sieve that remain. Your tmp array should be the primes found so far. Also you are using a recursive call which is confusing. I suggest simply grabbing the first value out of newArr which is a prime, add that prime to your list of primes, and then call arrayEcludingDividingByP to filter out the non-primes divisible by that prime. Repeat until newArr isEmpty which will happen when the conditional binding statement while let newP = newArr.first fails and the loop ends:
func getPrimes(arrPassed: [Int]) -> [Int] {
var primes: [Int] = []
var newArr = arrPassed
while let newP = newArr.first {
primes.append(newP)
newArr = arrayEcludingDivingByP(p: newP, arrToCheck: newArr)
}
return primes
}
print(getPrimes(arrPassed: Array(2...100)))
This can be further optimized because once newP * newP is greater than the largest number in newArr (newArr.last!) you are done and you can simply append newArr to primes and set newArr to [].
Also, arrayEcludingDivingByP(p: newP, arrToCheck: newArr) can be replaced by newArr.filter { $0 % newP != 0 }

Group an array of integers in a hash of ranges and counts

I have an array of integers like this:
[1, 1, 1, 2, 2, 4, 4, 5, 6, 11, 11, 12, 15, 22, 23, 23, 23, 31, 32, 32]
I am trying to convert this to a hash, grouping according to ranges at intervals of 10....
So, in this case it would be
{ [1..10] => 9, [11..20] => 4, [21..30] => 4, [31..40] => 3 }
I have tried a few things which haven't come close so it's a bit pointless putting them down here. I can convert the array to ranges
[1, 1, 1, 2, 2, 4, 4, 5, 6, 11, 11, 12, 15, 22, 23, 23, 23, 31, 32, 32].sort.uniq.inject([]) do |spans, n|
if spans.empty? || spans.last.last != n - 1
spans + [n..n]
else
spans[0..-2] + [spans.last.first..n]
end
end
But this is not what I am looking for. Any suggestions?
Hash[
your_array.group_by{|i| i / 10}.map{|k,v|
[(k*10+1..(k+1)*10), v.count]
}
]
#=> {1..10=>9, 11..20=>4, 21..30=>4, 31..40=>3}
arr.each_with_object(Hash.new(0)) do |e, hash|
i = e / 10
hash[i*10+1..i*10+10] += 1
end
#⇒ {
# 1..10 => 9,
# 11..20 => 4,
# 21..30 => 4,
# 31..40 => 3
# }
I've modified the example to have no numbers between 21 and 30, so that the hash should include the key-value pair 21..30=>0.
arr = [1, 1, 1, 2, 2, 4, 4, 5, 6, 11, 11, 12, 20, 32, 33, 33, 33, 41, 42, 42]
intervals = (1..arr.last-1).step(10).each_with_object({}) { |n,h| h[n..n+9] = 0 }
#=> {1..10=>0, 11..20=>0, 21..30=>0, 31..40=>0, 41..50=>0}
arr.each_with_object(intervals) do |n,intervals|
interval_end = 10*((n+9)/10)
intervals[interval_end-9..interval_end] += 1
end
#=> {1..10=>9, 11..20=>4, 21..30=>0, 31..40=>4, 41..50=>3}

array name stored in array, pushing to array - not working as expected

#board = {1=>0, 2=>0, 3=>0, 4=>0, 5=>0, 6=>0, 7=>0, 8=>"b", 9=>"r", 10=>"u", 11=>"c", 12=>0, 13=>0, 14=>"d", 15=>"h", 16=>"s", 17=>"l", 18=>0, 19=>0, 20=>"o", 21=>"i", 22=>"l", 23=>"b", 24=>0, 25=>0, 26=>"g", 27=>"t", 28=>"f", 29=>"e", 30=>0, 31=>0, 32=>0, 33=>0, 34=>0, 35=>0, 36=>0}
#words = {"shift"=>[16, 15, 21, 28, 27], "bell"=>[23, 29, 22, 17], "curb"=>[11, 10, 9, 8], "dog"=>[14, 20, 26]}
#col1 = [8, 14, 20, 26]
#col2 = [9, 15, 21, 27]
#col3 = [10, 16, 22, 28]
#col4 = [11, 17, 23, 29]
#rcol1 = Array.new
#rcol2 = Array.new
#rcol3 = Array.new
#rcol4 = Array.new
#cols = [#col1, #col2, #col3, #col4]
#rcols0 = [#rcol1, #rcol2, #rcol3, #rcol4]
out = #words["dog"]
out.each do |remove|
#board[remove] = 100
end
def colclone
nums = 0
#rcols0.each do |fixy|
a = #cols[nums]
a.each do |stick|
fixy[nums].push #board[stick]
end
nums += 1
end
end
Here's the actual code. I tried to simplify but I think I must have left something out.
I am working on a board game. What I want is
--> #rcol1 = [0, 1, 2, 3]
what I am getting is those results in my reference array instead
--> #rcols0 = [[0, 1, 2, 3], ...]
Any help would be greatly appreciated!
You have the wrong idea, or the wrong vocabulary, about how it works. names does not store the names of the arrays. names stores a reference to the Array objects. It doesn't matter what they're named.
array1 = [0, 1, 2]
array2 = [10,20,30]
names = [array1, array2]
# names[1] contains a reference to array2
# So this is the same as array2[2]
puts names[1][2] # 30
Your code works fine.
names.each do |update|
update.push 3
update.push 4
end
puts array1.inspect # [0, 1, 2, 3, 4]
Your solution seems to be working:
array1 = [1,2,3]
=> [1, 2, 3]
array2 = [4,5,6]
=> [4, 5, 6]
names = [array1, array2]
=> [[1, 2, 3], [4, 5, 6]]
names.each do |update|
update.push 8
update.push 9
end
=> [[1, 2, 3, 8, 9], [4, 5, 6, 8, 9]]
array1
=> [1, 2, 3, 8, 9]
array2
=> [4, 5, 6, 8, 9]
I think something like this is what you're looking for:
array1 = [0, 1, 2]
array2 = [10, 11, 12]
array3 = [20, 21, 22]
names = [array1, array2, array3]
names.each do |array|
i = array[array.length-1] + 1
array.push(i,i+1)
end
p array1
p array2
p array3
p names
Output for the above is:
[0, 1, 2, 3, 4] #array1
[10, 11, 12 ,13, 14] #array2
[20, 21, 22, 23, 24] #array3
[[0, 1, 2, 3, 4], [10, 11, 12, 13, 14], [20, 21, 22, 23, 24]] #names array
Modify and/or extend the code to suit your needs.

Testing if a player is standing on certain tiles of an integer array

I am trying to make a game in which a player will only fall if they aren't standing on specific tiles. My map is generated using an integer array that corresponds with various tile types. I was wondering if there is any way to test if the tile below the player is a certain tile, besides making an if else statement for every tile. I have given an example of one of the maps and how I am testing if a player is standing on it.
int[][] map3 = { //grid3
{ 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6, 6 },
{ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
{ 6, 6, 6, 6, 6, 0, 6, 7, 6, 6, 6, 6, 6, 6, 6, 6 },
{ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6 },
{ 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 6, 6, 6, 6, 6 },
{ 1, 1, 1, 1, 4, 6, 6, 6, 6, 6, 6, 6, 6, 0, 6, 0 },
{ 9, 9, 9, 9, 9, 5, 1, 1, 1, 1, 1, 4, 6, 6, 6, 6 },
{ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 1, 1, 1 },
{ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 },
{ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 }, };
if (grid3.getTile( (int) playerX, (int) playerY) != grid3.map[7][4]) {
player.setY((float) ((float) player.getY() - 0.7));
}
I would repeat this process for every ground tile.
You should just be able to use nested for loops to iterate over your arrays.
It would look something like this.
for(int c = 0; c < grid3.map.length; c++){
for(int x = 0; x < grid3.map[c].length){
if (grid3.getTile( (int) playerX, (int) playerY) != grid3.map[c][x])
player.setY((float) ((float) player.getY() - 0.7));
}
}

Resources