Convert this below array into matrix
Array
let ptsArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
Matrix
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
To find adjacent points in uniderectional like an below image
Expected output
(0,1) (0,6)
(1,2) (1,7)
(2,3) (2,8)
(3,4) (3,9)
(4,5) (4,10)
(5,11)
(6,7) (6,12)
(7,8) (7,13)
(8,9) (8,14)
(9,10) (9,15)
(10,11) (10,16)
(11,17)
(12,13)
(13,14)
(14,15)
(15,16)
(16,17)
My failed approach
for i in 0..<pointsArray.count-1{
if (i+1)%6 == 0 && i != 0{
print("Connection (\(i),\(i+6))")
nodesArray[i].addConnection(to: nodesArray[i+6], bidirectional: true, weight: 1)
}
if i>=pointsArray.count-6{
print("Connection (\(i),\(i+1))")
nodesArray[i].addConnection(to: nodesArray[i+1], bidirectional: true, weight: 1)
}
else{
print("Connection (\(i),\(i+1)) (\(i),\(i+6))")
nodesArray[i].addConnection(to: nodesArray[i+1], bidirectional: true, weight: 1)
nodesArray[i].addConnection(to: nodesArray[i+6], bidirectional: true, weight: 1)
}
}
Output:
Connection (0,1) (0,6)
Connection (1,2) (1,7)
Connection (2,3) (2,8)
Connection (3,4) (3,9)
Connection (4,5) (4,10)
Connection (5,11)
Connection (5,6) (5,11)
Connection (6,7) (6,12)
Connection (7,8) (7,13)
Connection (8,9) (8,14)
Connection (9,10) (9,15)
Connection (10,11) (10,16)
Connection (11,17)
Connection (11,12) (11,17)
Connection (12,13)
Connection (13,14)
Connection (14,15)
Connection (15,16)
Connection (16,17)
In the desired output, I guess that it's missing (9,15), (10,11), (10,16) and that (10,15) isn't valid.
If we think about your desired output, we notice something.
Let's name width = 6, it's the "width" of your matrix.
We see the pattern:
(value, value + 1), (value, value + width)
With some excluded tests: does (value + width) exists ? And we are not at the end of the width.
Let's, with a little reduce method:
let ptsArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
let width = 6
let tuples = ptsArray.indices.reduce(into: [(Int, Int)]()) { partialResult, anIndex in
if ptsArray.count > anIndex.advanced(by: 1) && anIndex % width != width - 1 {
let newValue = (ptsArray[anIndex], ptsArray[anIndex.advanced(by: 1)])
print(newValue)
partialResult.append(newValue)
}
if ptsArray.count > anIndex.advanced(by: width) {
let newValue = (ptsArray[anIndex], ptsArray[anIndex.advanced(by: width)])
print(newValue)
partialResult.append(newValue)
}
return
}
print(tuples)
I used "index", because in fact, points are in order here, but it could be any value, no? So let's use the index instead.
So, with something a little more generic:
extension Array {
func coupling(with width: Int) -> [(Element, Element)] {
let couples = indices.reduce(into: [(Element, Element)]()) { partialResult, anIndex in
if count > anIndex.advanced(by: 1) && anIndex % width != width - 1 {
let newValue = (self[anIndex], self[anIndex.advanced(by: 1)])
partialResult.append(newValue)
}
if count > anIndex.advanced(by: width) {
let newValue = (self[anIndex], self[anIndex.advanced(by: width)])
partialResult.append(newValue)
}
return
}
return couples
}
}
Use:
let ptsArray = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
let tuples2 = ptsArray. coupling(with: width)
print(tuples2)
let lettersArray = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P", "Q", "R"]
let tuples3 = lettersArray. coupling(with: width)
print(tuples3)
Another approach - convert your ptsArray into a 2-D matrix:
var matrix: [[Int]] = []
let numCols: Int = 6
var numRows: Int = 0
let ptsArray: [Int] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
for i in stride(from: 0, to: ptsArray.count, by: numCols) {
// make sure we don't exceed the array limit
if ptsArray.count >= i+numCols {
matrix.append(Array(ptsArray[i..<i+numCols]))
}
}
numRows = matrix.count
You can now get the right and down values (if they exist) like this:
func getPair2D(_ n: Int) -> (Int?, Int?) {
let thisRow = n / numCols
let thisCol = n % numCols
let numToRight = thisCol < numCols-1 ? matrix[thisRow][thisCol+1] : nil
let numToDown = thisRow < numRows-1 ? matrix[thisRow+1][thisCol] : nil
return (numToRight, numToDown)
}
and this will print out the results:
for i in 0..<ptsArray.count {
let (n1, n2) = getPair2D(i)
var str = ""
if let n1 = n1 {
str += "(\(i), \(n1))"
}
if let n2 = n2 {
if !str.isEmpty { str += " " }
str += "(\(i), \(n2))"
}
print(str)
}
Here's a simple view controller that let's you tap any number to show the "right and down" matches:
class MatrixVC: UIViewController {
var matrix: [[Int]] = []
var views: [UIView] = []
let numCols: Int = 6
var numRows: Int = 0
override func viewDidLoad() {
super.viewDidLoad()
let ptsArray: [Int] = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
for i in stride(from: 0, to: ptsArray.count, by: numCols) {
if ptsArray.count >= i+numCols {
matrix.append(Array(ptsArray[i..<i+numCols]))
}
}
numRows = matrix.count
let oStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.distribution = .fillEqually
v.spacing = 2
return v
}()
var n = 0
for r in 0..<numRows {
let rStack: UIStackView = {
let v = UIStackView()
v.axis = .horizontal
v.distribution = .fillEqually
v.spacing = 2
return v
}()
for c in 0..<numCols {
let v = UILabel()
v.textAlignment = .center
v.text = "\(ptsArray[n])"
v.isUserInteractionEnabled = true
let t = UITapGestureRecognizer(target: self, action: #selector(gotTap(_:)))
v.addGestureRecognizer(t)
rStack.addArrangedSubview(v)
views.append(v)
if c < numCols-1 {
let iv = UIImageView(image: UIImage(systemName: "arrow.right"))
rStack.addArrangedSubview(iv)
}
n += 1
}
oStack.addArrangedSubview(rStack)
if r < numRows-1 {
let rStack: UIStackView = {
let v = UIStackView()
v.axis = .horizontal
v.distribution = .fillEqually
v.spacing = 2
return v
}()
for c in 0..<numCols {
let iv = UIImageView(image: UIImage(systemName: "arrow.down"))
rStack.addArrangedSubview(iv)
if c < numCols-1 {
let v = UIView()
rStack.addArrangedSubview(v)
}
}
oStack.addArrangedSubview(rStack)
}
}
oStack.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(oStack)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
oStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 40.0),
oStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -40.0),
oStack.centerXAnchor.constraint(equalTo: g.centerXAnchor),
oStack.centerYAnchor.constraint(equalTo: g.centerYAnchor),
])
}
#objc func gotTap(_ g: UITapGestureRecognizer) {
guard let v = g.view as? UILabel,
let t = v.text,
let n = Int(t)
else { return }
// if the tapped label is yellow, let's just deselect all
let deselecting: Bool = views[n].backgroundColor == .yellow
views.forEach { $0.backgroundColor = .clear }
if deselecting {
return()
}
views[n].backgroundColor = .yellow
let (n1, n2) = getPair2D(n)
if let n1 = n1 {
views[n1].backgroundColor = .yellow
}
if let n2 = n2 {
views[n2].backgroundColor = .yellow
}
}
func getPair2D(_ n: Int) -> (Int?, Int?) {
let thisRow = n / numCols
let thisCol = n % numCols
let numToRight = thisCol < numCols-1 ? matrix[thisRow][thisCol+1] : nil
let numToDown = thisRow < numRows-1 ? matrix[thisRow+1][thisCol] : nil
return (numToRight, numToDown)
}
}
It looks like this:
Tapping any number will highlight the pair:
Tapping a "highlighted" number will "un-highlight" all numbers.
I am writing a program in Swift which requires a method that uses specification of two CGPoints and returns all points in a straight line in-between them. At the moment I am trialling the following method, but it is very glitchy and refuses to get all points for some lines. I was just wondering if there is a more efficient way of doing this?
func addPointsInLine(#start: CGPoint, end: CGPoint){
var speed = 0
var startNo = trackPoints.count
var endNo = startNo
var xDiff = start.x - end.x
var yDiff = start.y - end.y
var xChange = 0.0
var yChange = 0.0
var newPointX = start.x
var newPointY = start.y
var ended = false
xChange = Double(xDiff) / Double(yDiff)
yChange = Double(yDiff) / Double(xDiff)
/*if(xDiff > 0){
xChange = sqrt(xChange * xChange)
}
if(yDiff > 0){
yChange = sqrt(yChange * yChange)
}*/
println("xc \(xChange)")
println("yc \(yChange)")
var y = Double(start.y)
var x = Double(start.x)
while !ended {
println(trackPoints.count)
speed++
endNo++
if(CGPointMake(newPointX, newPointY) == end){
ended = true
}
if(yChange > xChange){
y++
x += xChange
trackPoints.append(TrackPoint(x: Int(x), y: Int(y)))
if(CGFloat(Int(y)) == end.y){
ended = true
println("end")
//break
}
/* if(yChange > 0){
if(CGFloat(Int(y)) > end.y){
ended = true
println("end>y")
// break
}
}
if(yChange < 0){
if(CGFloat(Int(y)) < end.y){
ended = true
println("end<y")
//break
}
}*/
if(xChange > 0){
if(CGFloat(Int(x)) >= end.x){
ended = true
println("end>x")
//break
}
}
if(xChange < 0){
if(CGFloat(Int(x)) <= end.x){
ended = true
println("end<x")
//break
}
}
} else {
x++
y += yChange
trackPoints.append(TrackPoint(x: Int(x), y: Int(y)))
if(CGFloat(Int(x)) == end.x){
ended = true
println("end")
//break
}
/* if(xChange > 0){
if(CGFloat(Int(x)) >= end.x){
ended = true
println("end>x")
//break
}
}
if(xChange < 0){
if(CGFloat(Int(x)) <= end.x){
ended = true
println("end<x")
//break
}
}*/
if(yChange > 0){
if(CGFloat(Int(y)) > end.y){
ended = true
println("end>y")
// break
}
}
if(yChange < 0){
if(CGFloat(Int(y)) < end.y){
ended = true
println("end<y")
//break
}
}
}
}
println("finished")
var i = startNo
println(startNo)
println(endNo)
while i < endNo {
trackPoints[i].speed = speed
i++
}
println("finish2")
}
I think firstly finding all points isn't possible because there are infinite points in a straight line. Take example of line joining (0,0) to (1, 0). All the following points and many more are on the said line (0.00001,0) (0.0000000000001,0) (0.01,0)
So you need to limit the amount of points you need to find like all the points with Integer co-ordinates. All the points 1 unit apart, starting from starting point etc.
Next you can use one of equations of line to get points: Equations of Line
Try this,
func findAllPointsBetweenTwoPoints(startPoint : CGPoint, endPoint : CGPoint) {
var allPoints :[CGPoint] = [CGPoint]()
let deltaX = fabs(endPoint.x - startPoint.x)
let deltaY = fabs(endPoint.y - startPoint.y)
var x = startPoint.x
var y = startPoint.y
var err = deltaX-deltaY
var sx = -0.5
var sy = -0.5
if(startPoint.x<endPoint.x){
sx = 0.5
}
if(startPoint.y<endPoint.y){
sy = 0.5;
}
repeat {
let pointObj = CGPoint(x: x, y: y)
allPoints.append(pointObj)
let e = 2*err
if(e > -deltaY)
{
err -= deltaY
x += CGFloat(sx)
}
if(e < deltaX)
{
err += deltaX
y += CGFloat(sy)
}
} while (round(x) != round(endPoint.x) && round(y) != round(endPoint.y));
allPoints.append(endPoint)
}
In my adding function where answerLabel.text is it is giving me an error. It says 'String' is not convertible to 'Int' and I'm trying to get what I got from the secondStep2 and put in the parameters of my functions
//Adding Function
changingSignsLabel.text = "+"
let firstDenomInTextField:Double! = (firstDenominatorTextField.text as NSString).doubleValue
let firstNumInTextField:Double! = (firstNumeratorTextField.text as NSString).doubleValue
let firstWholeInTextField:Double! = (firstWholeNumberTextField.text as NSString).doubleValue
let secondDenomInTextField:Double! = (secondDenominatorTextField.text as NSString).doubleValue
let secondNumInTextField:Double! = (secondNumeratorTextField.text as NSString).doubleValue
let secondWholeInTextField:Double! = (secondWholeNumberTextField.text as NSString).doubleValue
var firstStep = firstDenomInTextField! * firstWholeInTextField! / firstDenomInTextField!
var secondStep = firstStep + firstNumInTextField! / firstDenomInTextField!
var thirdStep = secondDenomInTextField! * secondWholeInTextField! / secondDenomInTextField!
var fourthStep = thirdStep + secondNumInTextField! / secondDenomInTextField!
var calculatedAnswer = (secondStep + fourthStep)
answerLabel.hidden = false
var firstStep2 = calculatedAnswer / 1
var secondStep2 = "\(firstStep2 * 10 * 10)"
answerLabel.text = printSimplifiedFraction(Numerator: secondStep2)
My Function
func printSimplifiedFraction(Numerator numerator: Int, Denominator denominator: Int = 100)
{
var finalNumerator = numerator;
var finalDenominator = denominator;
var wholeNumbers:Int = numerator / denominator;
var remainder:Int = numerator % denominator;
//println("wholeNumbers = \(wholeNumbers), remainder = \(remainder)");
//println("\(denominator) % \(remainder) = \(denominator % remainder)");
if(remainder > 0)
{
// see if we can simply the fraction part as well
if(denominator % remainder == 0) // no remainder means remainder can be simplified further
{
finalDenominator = denominator / remainder;
finalNumerator = remainder / remainder;
}
else
{
finalNumerator = remainder;
finalDenominator = denominator;
}
}
if(wholeNumbers > 0 && remainder > 0)
{
// prints out whole number and fraction parts
println("Simplified fraction of \(numerator)/\(denominator) = \(wholeNumbers) \(finalNumerator)/\(finalDenominator)");
}
else if (wholeNumbers > 0 && remainder == 0)
{
// prints out whole number only
println("Simplified fraction of \(numerator)/\(denominator) = \(wholeNumbers)");
}
else
{
// prints out fraction part only
println("Simplified fraction of \(numerator)/\(denominator) = \(finalNumerator)/\(finalDenominator)");
}
}
My Question how do I get the function to accept my variable?
I believe this is what you want, first in your adding function it should be:
var firstStep2 = calculatedAnswer / 1
var secondStep2 = Int(firstStep2 * 10 * 10)
answerLabel.text = printSimplifiedFraction(Numerator: secondStep2)
Then your print... method should be changed like this (note that it's returning a String):
func printSimplifiedFraction(Numerator numerator: Int, Denominator denominator: Int = 100) -> String
{
// I haven't looked into this bit
...
if(wholeNumbers > 0 && remainder > 0)
{
return ("Simplified fraction of \(numerator)/\(denominator) = \(wholeNumbers) \(finalNumerator)/\(finalDenominator)")
}
else if (wholeNumbers > 0 && remainder == 0)
{
return ("Simplified fraction of \(numerator)/\(denominator) = \(wholeNumbers)")
}
else
{
return ("Simplified fraction of \(numerator)/\(denominator) = \(finalNumerator)/\(finalDenominator)")
}
}
Also, looking through your code I think you can simplify the logic quite a bit (I've also converted to Integers as you said you wanted in the comments):
let firstDenomInTextField = firstDenominatorTextField.text.toInt()
let firstNumInTextField = firstNumeratorTextField.text.toInt()
let firstWholeInTextField = firstWholeNumberTextField.text.toInt()
let secondDenomInTextField = secondDenominatorTextField.text.toInt()
let secondNumInTextField = secondNumeratorTextField.text.toInt()
let secondWholeInTextField = secondWholeNumberTextField.text.toInt()
var firstStep = firstWholeInTextField! + firstNumInTextField! / firstDenomInTextField!
var secondStep = secondWholeInTextField! + secondNumInTextField! / secondDenomInTextField!
var calculatedAnswer = (firstStep + secondStep)
var numerator = Int(calculatedAnswer * 10 * 10)
answerLabel.text = printSimplifiedFraction(Numerator: numerator)
Try this:
var str:String = "abc"
var a:Int? = str.toInt()
if (a != nil) {
printSimplifiedFraction(Numerator: str!)
}
And add a return value to your function
func printSimplifiedFraction(Numerator numerator: Int, Denominator denominator: Int = 100) ->String {
var finalNumerator = numerator;
var finalDenominator = denominator;
var wholeNumbers:Int = numerator / denominator;
var remainder:Int = numerator % denominator;
if(remainder > 0)
{
// see if we can simply the fraction part as well
if(denominator % remainder == 0) // no remainder means remainder can be simplified further
{
finalDenominator = denominator / remainder;
finalNumerator = remainder / remainder;
}
else
{
finalNumerator = remainder;
finalDenominator = denominator;
}
}
var result:String = "Simplified fraction of \(numerator)/\(denominator) = ";
if(wholeNumbers > 0 && remainder > 0)
{
// prints out whole number and fraction parts
result += "\(wholeNumbers) \(finalNumerator)/\(finalDenominator)"
}
else if (wholeNumbers > 0 && remainder == 0)
{
// prints out whole number only
result += "\(wholeNumbers)"
}
else
{
// prints out fraction part only
result += "\(finalNumerator)/\(finalDenominator)"
}
println("\(result)")
return result
}
this printSimplifiedFraction is not returning any value, but you are assigning to the answerLabel.text, i think this is the problem.
If you want to assign a value which is returned form fuction, add return type to the fuction and return a value.
func printSimplifiedFraction(Numerator numerator: Int, Denominator denominator: Int = 100) -> String {
//add end of your function
return yourValue;
}
Check this link
In Your Code do like this
var secondStep2 = (firstStep2 * 10 * 10)
answerLabel.text = printSimplifiedFraction(Numerator: secondStep2)
func printSimplifiedFraction(Numerator numerator: Int, Denominator denominator: Int = 100) -> String
{
var finalNumerator = numerator;
var finalDenominator = denominator;
var wholeNumbers:Int = numerator / denominator;
var remainder:Int = numerator % denominator;
//println("wholeNumbers = \(wholeNumbers), remainder = \(remainder)");
//println("\(denominator) % \(remainder) = \(denominator % remainder)");
if(remainder > 0)
{
// see if we can simply the fraction part as well
if(denominator % remainder == 0) // no remainder means remainder can be simplified further
{
finalDenominator = denominator / remainder;
finalNumerator = remainder / remainder;
}
else
{
finalNumerator = remainder;
finalDenominator = denominator;
}
}
var returnValue :String
if(wholeNumbers > 0 && remainder > 0)
{
returnValue = "Simplified fraction of \(numerator)/\(denominator) = \(wholeNumbers) \(finalNumerator)/\(finalDenominator)"
}
else if (wholeNumbers > 0 && remainder == 0)
{
returnValue = "Simplified fraction of \(numerator)/\(denominator) = \(wholeNumbers)"
}
else
{
returnValue = "Simplified fraction of \(numerator)/\(denominator) = \(finalNumerator)/\(finalDenominator)"
}
return returnValue
}