Swift using eratosthenes method to get prime numbers - arrays

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 }

Related

Most efficient way to select elements in 2d array in Ruby

Let's say I have 2d array (or matrix) like,
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
And, I've to select all elements in eight directions of a certain element matrix[i][j], so I know,
up and down elements will have same j
left and right elements will have same i
back-inclined diagonal (\) elements will have same diff i-j
front-inclined diagonal (/) elements will have same sum i+j
How to select those elements, easily and efficiently? Any direct method?
For example, if my element is 4, then my selection should yield, [1, 7, 5, 6, 2, 8]. If it is, 5, then selection should be all except 5.
Edit: I've coded any solution yet, as I thought it'll be very poor, but here is my idea. Try it online!
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
res = []
i = 0
j = 1
# let [i,j] be index of my element
matrix.each_with_index{|row,r| row.each_with_index{|col,c|
res << col if c == j || r == i || r+c == i+j || r-c == i-j
}}
p res
m is the matrix you have taken from a user that is a symmetric or non-symmetric 2-dimensional array.
# inputs
m = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]
p, q = 1, 0 # co-ordinate of number 4
# code for output
i, j, result = m.size, m[0].size, []
i.times { |r| result.push(m[r][q]) if r != p }
j.times { |c| result.push(m[p][c]) if c != q }
i.times do |r|
j.times do |c|
result.push(m[r][c]) if [p,q] != [r,c] && (p-r).abs == (q-c).abs
end
end
> result
=> [1, 7, 5, 6, 2, 8]
Note: if the order of output is not needed to be preserved, we can manage with only 2 loops
Code
def extract(matrix, row, col)
last_row = matrix.size-1
last_col = matrix.first.size-1
diag_sum = row + col
diag_first_row = diag_sum - [diag_sum, last_col].min
diag_last_row = [last_row, diag_sum].min
ante_diag_diff = row - col
ante_diag_first_row = [ante_diag_diff, 0].max
ante_diag_last_row = ante_diag_diff +
[last_col, last_row - ante_diag_diff].min
arr = []
(0..last_col).each { |j| arr << matrix[row][j] unless j == col }
(0..last_row).each { |i| arr << matrix[i][col] unless i == row }
(diag_first_row..diag_last_row).each do |i|
arr << matrix[i][diag_sum - i] unless i == row
end
(ante_diag_first_row..ante_diag_last_row).each do |i|
arr << matrix[i][i - ante_diag_diff] unless i == row
end
arr
end
Example
matrix = Array.new(5) { Array.new(5) { rand(10..99) } }
#=> [[52, 29, 61, 35, 27],
# [68, 99, 67, 18, 67],
# [79, 10, 73, 15, 36],
# [49, 94, 28, 24, 53],
# [37, 26, 65, 65, 43]]
(0..4).each do |i|
(0..4).each do |j|
puts "#{i}, #{j}: #{extract(matrix,i,j)}"
end
end
i j
----------------------------------------------------------------------
0, 0: [29, 61, 35, 27, 68, 79, 49, 37, 99, 73, 24, 43]
0, 1: [52, 61, 35, 27, 99, 10, 94, 26, 68, 67, 15, 53]
0, 2: [52, 29, 35, 27, 67, 73, 28, 65, 99, 79, 18, 36]
0, 3: [52, 29, 61, 27, 18, 15, 24, 65, 67, 10, 49, 67]
0, 4: [52, 29, 61, 35, 67, 36, 53, 43, 18, 73, 94, 37]
1, 0: [99, 67, 18, 67, 52, 79, 49, 37, 29, 10, 28, 65]
1, 1: [68, 67, 18, 67, 29, 10, 94, 26, 61, 79, 52, 73, 24, 43]
1, 2: [68, 99, 18, 67, 61, 73, 28, 65, 35, 10, 49, 29, 15, 53]
1, 3: [68, 99, 67, 67, 35, 15, 24, 65, 27, 73, 94, 37, 61, 36]
1, 4: [68, 99, 67, 18, 27, 36, 53, 43, 15, 28, 26, 35]
2, 0: [10, 73, 15, 36, 52, 68, 49, 37, 61, 99, 94, 65]
2, 1: [79, 73, 15, 36, 29, 99, 94, 26, 35, 67, 49, 68, 28, 65]
2, 2: [79, 10, 15, 36, 61, 67, 28, 65, 27, 18, 94, 37, 52, 99, 24, 43]
2, 3: [79, 10, 73, 36, 35, 18, 24, 65, 67, 28, 26, 29, 67, 53]
2, 4: [79, 10, 73, 15, 27, 67, 53, 43, 24, 65, 61, 18]
3, 0: [94, 28, 24, 53, 52, 68, 79, 37, 35, 67, 10, 26]
3, 1: [49, 28, 24, 53, 29, 99, 10, 26, 27, 18, 73, 37, 79, 65]
3, 2: [49, 94, 24, 53, 61, 67, 73, 65, 67, 15, 26, 68, 10, 65]
3, 3: [49, 94, 28, 53, 35, 18, 15, 65, 36, 65, 52, 99, 73, 43]
3, 4: [49, 94, 28, 24, 27, 67, 36, 43, 65, 29, 67, 15]
4, 0: [26, 65, 65, 43, 52, 68, 79, 49, 27, 18, 73, 94]
4, 1: [37, 65, 65, 43, 29, 99, 10, 94, 67, 15, 28, 49]
4, 2: [37, 26, 65, 43, 61, 67, 73, 28, 36, 24, 79, 94]
4, 3: [37, 26, 65, 43, 35, 18, 15, 24, 53, 68, 10, 28]
4, 4: [37, 26, 65, 65, 27, 67, 36, 53, 52, 99, 73, 24]
Explanation
First observe that if the target element is in row i and column j, the elements [p,q] on the diagonal that passes through that point have the property that p+q == i+j. Similarly, the elements [p,q] on the ante-diagonal that passes through that point have the property that p-q == i-j
Suppose
row = 1
col = 2
then
last_row = matrix.size-1
#=> 4
last_col = matrix.first.size-1
#=> 4
diag_sum = row + col
#=> 3
diag_first_row = diag_sum - [diag_sum, last_col].min
#=> 0
diag_last_row = [last_row, diag_sum].min
#=> 3
ante_diag_diff = row - col
#=> -1
ante_diag_first_row = [ante_diag_diff, 0].max
#=> 0
ante_diag_last_row = ante_diag_diff +
[last_col, last_row - ante_diag_diff].min
#=> 3
The remaining calculations are straightforward.
Here's a variant of the above that uses less code and may be slightly less efficient.
def extract(matrix, row, col)
row_range = 0..matrix.size-1
col_range = 0..matrix.first.size-1
diag_sum = row + col
ante_diag_diff = row - col
arr = []
col_range.each { |j| arr << matrix[row][j] unless j == col }
row_range.each do |i|
next if i == row
arr << matrix[i][col]
j = diag_sum - i
arr << matrix[i][j] if col_range.cover?(j)
j = i - ante_diag_diff
arr << matrix[i][j] if col_range.cover?(j)
end
arr
end
Here is sample code, you can modify/simplify it further
class Matrix
attr_reader :arr, :ele
def initialize(arr, ele)
#arr = arr
#ele = ele
end
def find_elements
position = arr.flatten.index(ele)
len = arr.length
x = position % len
y = position / len
horizontal_elements(y) + vertical_elements(x, y, len) + remaining_elements(x, y, len)
end
def horizontal_elements y
arr[y] - [ele]
end
def vertical_elements x, y, len
rows = (0..(len-1)).to_a - [y]
rows.map{|row| arr[row][x] }
end
def remaining_elements(x, y, len)
rows = []
rows << y + 1 if y + 1 < len
rows << y - 1 if y - 1 >= 0
c_rows = []
c_rows << x + 1 if x + 1 < len
c_rows << x - 1 if x - 1 >= 0
rows.map{|row| c_rows.map{|c_row| arr[row][c_row] } }.flatten
end
end
matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
ele = 4
(1..9).each do |i|
puts '*' * 20
puts "For #{i}"
puts Matrix.new(matrix, i).find_elements.inspect
puts '*' * 20
end
O/P will be something like following
Desktop $ ruby something.rb
********************
For 1
[2, 3, 4, 7, 5]
********************
********************
For 2
[1, 3, 5, 8, 6, 4]
********************
********************
For 3
[1, 2, 6, 9, 5]
********************
********************
For 4
[5, 6, 1, 7, 8, 2]
********************
********************
For 5
[4, 6, 2, 8, 9, 7, 3, 1]
********************
********************
For 6
[4, 5, 3, 9, 8, 2]
********************
********************
For 7
[8, 9, 1, 4, 5]
********************
********************
For 8
[7, 9, 2, 5, 6, 4]
********************
********************
For 9
[7, 8, 3, 6, 5]
********************
A recursive way
I'd like to propose a different approach, not tested if it is more or less efficient but can provide some control on order and more.
Lets start with this matrix, where elements tell their indexing:
mat = [
['00', '01', '02'],
['10', '11', '12'],
['20', '21', '22'],
['30', '31', '32']
]
And define an helper method just to get the shape of the matrix and to check which is well formed:
def shape(mat)
raise 'Out of shape' if mat.map(&:size).uniq.size > 1
return mat.size, mat[0].size
end
Implementation
Now, let's define a method that takes as input the starting point, the limits of the matrix (shape) and the direction.
def walk(i_0, j_0, i_max, j_max, direction, res=[])
d_i, d_j = direction
next_step = [i_0 + d_i, j_0 + d_j]
if [-1, i_max].include?(next_step[0]) || [-1, j_max].include?(next_step[1])
return res
end
res << next_step
i_0, j_0 = next_step
walk(i_0, j_0, i_max, j_max, direction, res)
end
The method returns the list of indexes starting from the origin and walking along the direction.
Usage examples
Example 1
i_0, j_0 = [2, 0]
i_max, j_max = shape(mat)
direction = [-1, 1]
walk(i_0, j_0, *shape(mat), direction)
#=> [[1, 1], [0, 2]]
Example 2
You can use it to extract the indexes given a list of directions.
It's possible to arrange the list of directions to give a scan order (clockwise, cclockwise) or just skip some directions, as you will.
directions = [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
i_0, j_0 = [2, 0]
directions = [[1, 0], [-1, 0], [0, 1], [0, -1], [1, 1], [1, -1], [-1, 1], [-1, -1]]
directions.flat_map { |direction| walk(i_0, j_0, *shape(mat), direction) }
#=> [[3, 0], [1, 0], [0, 0], [2, 1], [2, 2], [3, 1], [1, 1], [0, 2]]
Example 3
(Which is an extension of example 2)
You can directly get the elements from the matrix:
res = directions.flat_map do |direction|
walk(i_0, j_0, *shape(mat), direction).map do |coords|
i, j = coords
mat[i][j]
end
end
res
#=> ["30", "10", "00", "21", "22", "31", "11", "02"]
It can be possible to use a longer step (eg. direction = [2, 2]) upgrading the walk method.

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 Joining 2 Arrays in Specific Order

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"

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}

Get every n-elements of array

How to select every n-elements (e.g. six) of an array using Ruby 1.9+? Example:
a = [0, 1, 2, 3, 4, ... , 33]
# solution
# => [[0, 1, 2, 3, 4, 5], [6, 7, 8, 9, 10, 11], ... ]
Enumerable#each_slice
Iterates the given block for each
slice of elements. If no block is
given, returns an enumerator.
e.g.:
(1..10).each_slice(3) {|a| p a}
# outputs below
[1, 2, 3]
[4, 5, 6]
[7, 8, 9]
[10]
Use as:
irb(main):002:0> a = Array(1..33)
=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33]
irb(main):003:0> a.each_slice(5) # no good
=> #<Enumerable::Enumerator:0x47ae6e8>
irb(main):004:0> a.each_slice(5).to_a # good
=> [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15], [16, 17, 18, 19, 20], [21, 22, 23, 24, 25], [26, 27, 28, 29, 30], [31, 32, 33]]

Resources