I want to create an array that is 3d. Array will be 5*5*infinite (the last or the innermost array will probably has like 3-5 object of type String).
I tried something like this:
var array3D = [[[String]]]()
and tried to add new string like this
array3D[ii][yy] += y.components(separatedBy: ";")
But had problems adding new arrays or strings to that. And got error of exc bad instruction
In school I have 5 lessons per day. So in week there is 25 lessons, and I want to make an iPhone app that represent my timetable.
A multidimensional array is just an array of arrays. When you say
var array3D = [[[String]]]()
What you've created is one empty array, which expects the values you add to it to be of type [[String]]. But those inner arrays don't exist yet (much less the inner inner arrays inside them). You can't assign to array3D[ii] because ii is beyond the bounds of your empty array, you can't assign to array3D[ii][yy] because array3D[ii] doesn't exist, and you can't append to an array in array3D[ii][yy] because array3D[ii][yy] doesn't exist.
Because your outer and middle levels of array are fixed in size (5 by 5 by n), you could easily create them using Array.init(count:repeatedValue:):
let array3D = [[[String]]](count: 5, repeatedValue:
[[String]](count: 5, repeatedValue: []))
(Here the innermost arrays are empty, since it appears you plan to always fill the by appending.)
However, it also looks like your use case expects a rather sparse data structure. Why create all those arrays if most of them will be empty? You might be better served by a data structure that lets you decouple the way you index elements from the way they're stored.
For example, you could use a Dictionary where each key is some value that expresses a (day, lesson, index) combination. That way the (day, lesson, index) combinations that don't have anything don't need to be accounted for. You can even wrap a nice abstraction around your encoding of combos into keys by defining your own type and giving it a subscript operator (as alluded to in appzYourLife's answer).
I slightly modified the Matrix struct provided by The Swift Programming Language
struct Matrix<ElementType> {
let rows: Int, columns: Int
var grid: [[ElementType]]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(count: rows * columns, repeatedValue: [])
}
func indexIsValidForRow(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> [ElementType] {
get {
assert(indexIsValidForRow(row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValidForRow(row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
Usage
Now you can write
var data = Matrix<String>(rows: 5, columns: 5)
data[0, 0] = ["Hello", "World"]
data[0, 0][0] // Hello
Related
Is there a MathNET.Numerics equivalent of Matlab’s sortrows(A, column), where A is a Matrix<double>?
To recall Matlab's documentation:
B = sortrows(A,column) sorts A based on the columns specified in the
vector column. For example, sortrows(A,4) sorts the rows of A in
ascending order based on the elements in the fourth column.
sortrows(A,[4 6]) first sorts the rows of A based on the elements in
the fourth column, then based on the elements in the sixth column to
break ties.
Similar to my answer to your other question, there's nothing inbuilt but you could use Linq's OrderBy() method on an Enumerable of the matrix's rows. Given a Matrix<double> x,
x.EnumerateRows() returns an Enumerable<Vector<double>> of the matrix's rows. You can then sort this enumerable by the first element of each row (if that's what you want).
In C#,
var y = Matrix<double>.Build.DenseOfRows(x.EnumerateRows().OrderBy(row => row[0]));
Example
Writing this as an extension method:
public static Matrix<double> SortRows(this Matrix<double> x, int sortByColumn = 0, bool desc = false) {
if (desc)
return Matrix<double>.Build.DenseOfRows(x.EnumerateRows().OrderByDescending(row => row[sortByColumn]));
else
return Matrix<double>.Build.DenseOfRows(x.EnumerateRows().OrderBy(row => row[sortByColumn]));
}
which you can then call like so:
var y = x.SortRows(0); // Sort by first column
Here's a big fiddle containing everything
this is demo of iOS Charts library (LineChart) and I want to input my data instead of arc4random data.
My data is in Array so I have to approach with index but I can't understand the (0..<count).map { (i) -> ChartDataEntry code.
func setChartValues(_ count : Int = 24) {
let values = (0..<count).map { (i) -> ChartDataEntry in
let val = Double(arc4random_uniform(UInt32(count))+3)
return ChartDataEntry(x: Double(i), y: val)
}
let set1 = LineChartDataSet(entries: values , label : "DataSet 1")
let data = LineChartData(dataSet: set1)
self.lineChartView.data = data
}
It seems you are new to iOS and swift. What you are looking for is an understanding of the functionning of closures in swift, plus the map function which is called an high order function
from apple doc ( https://developer.apple.com/documentation/swift/array/3017522-map ) :
Returns an array containing the results of mapping the given closure over the sequence’s elements.
In other words it maps your array into another array, according to the trailing closure you passed as a parameter.
In your specific case here his how to read it :
(0..<count) : creates an array of count lengh
example : if count = 4 then (0..<count) is [0, 1, 2, 3]
As said previously the map function will transform each of your element into another ( therefore keeping the length of the array ).
in your case val = Double(arc4random_uniform(UInt32(count))+3) will be equal to a random number calculated with count value, and create a new ChartDataEntry with this random value.
to sum it up the whole code is just saying "I will create a count length array of random ChartDataEntry", I guess as a mockup
I suggest you to read about closures here :
https://medium.com/the-andela-way/closures-in-swift-8aef8abc9474
and high order functions ( such as map(_:) ) here :
https://medium.com/#abhimuralidharan/higher-order-functions-in-swift-filter-map-reduce-flatmap-1837646a63e8
let values = (0.. ChartDataEntry in
let val = Double(arc4random_uniform(UInt32(count))+3)
return ChartDataEntry(x: Double(i), y: val)
}
The value mapped and return is you can say a hash function. (arc4random).
It index you are taking is just setting X axis of the chart like 0 , 1 ,2 etc...
and your graph Y it set according to the functions return (arc4random)
var array: [Int] = []
//Here I make an array to try to dictate when to perform an IBaction.
func random() -> Int {
let rand = arc4random_uniform(52)*10+10
return Int(rand)
}
//this function makes a random integer for me
func finalRand() -> Int {
var num = random()
while (array.contains(num) == true){
if (num == 520){
num = 10
}else {
num += 10
}
}
array.append(num)
return num
}
The logic in the while statement is somewhat confusing, but you could try this:
var array:Array<Int> = []
func finalRand() -> Int {
var num = Int(arc4random_uniform(52)*10+10)
while array.contains(num) {
num = Int(arc4random_uniform(52)*10+10)
}
array.append(num)
return num
}
This way there will never be a repeat, and you have less boiler code.
There is probably a better method involving Sets, but I'm sorry I do not know much about that.
A few things:
Once your array has all 52 values, an attempt to add the 53rd number will end up in an infinite loop because all 52 values are already in your array.
In contemporary Swift versions, you can simplify your random routine to
func random() -> Int {
return Int.random(in: 1...52) * 10
}
It seems like you might want a shuffled array of your 52 different values, which you can reduce to:
let array = Array(1...52).map { $0 * 10 }
.shuffled()
Just iterate through that shuffled array of values.
If you really need to continue generating numbers when you’re done going through all of the values, you could, for example, reshuffle the array and start from the beginning of the newly shuffled array.
As an aside, your routine will not generate truly random sequence. For example, let’s imagine that your code just happened to populate the values 10 through 500, with only 510 and 520 being the final possible remaining values: Your routine is 51 times as likely to generate 510 over 520 for the next value. You want to do a Fisher-Yates shuffle, like the built-in shuffled routine does, to generate a truly evenly distributed series of values. Just generate array of possible values and shuffle it.
I am currently struggling with an error for a homework assignment in my coding class. We are creating a loop that loops through an array of gpa values and then adds it to a variable named totalGradePoints. The problem is that I am coming across an error when the loop runs:
Left side of mutating operator isn't mutable: 'gpa' is a 'let' constant
The error is on this line:
var totalGradePoints = Double()
for gpa in gpaValues {
let averageGPA: Double = gpa += totalGradePoints
}
Here is my full code:
//: Playground - noun: a place where people can play
import UIKit
// You are the university registrar processing a transfer student's transcripts that contains grades that are a mix of letters and numbers. You need to add them to our system, but first you need to convert the letters into grade points.
// Here's an array of the student's grades.
var transferGrades: [Any] = ["C", 95.2, 85, "D", "A", 93.23, "P", 90, 100]
// To prepare for converting the letters to numerical grades, create a function that returns a double, inside which you create a switch that will convert an A to a 95, B to 85, C to 75, D to 65, , P (for passing) to 75. Everything else will be a zero.
func gradeConverter(letterGrade: String) -> Double {
switch letterGrade {
case "A":
return 95
case "B":
return 85
case "C":
return 75
case "D":
return 65
case "P":
return 75
default: // Is this where everything else is zero?
return 0
}
}
// Create a new array called convertedGrades that stores doubles.
var convertedGrades: [Double] = [98.75, 75.5, 60.0, 100.0, 82.25, 87.5]
// Loop through the transferGrades array, inspecing each item for type and sending strings (your letter grades) to the function you just made and storing the returned double in your convertedGrades array. If your loop encounters a double, you can place it directly into the new array without converting it. It it encounters an int, you will need to convert it to a double before storing it. Print the array. (You may notice that some of your doulbes are stored with many zeros in the decimal places. It's not an error, so you can ignore that for now)
for grade in transferGrades {
if let gradeAsString = grade as? String {
gradeConverter(letterGrade: gradeAsString)
} else if let gradeAsDouble = grade as? Double {
transferGrades.append(gradeAsDouble)
} else if let gradeAsInt = grade as? Int {
Double(gradeAsInt)
transferGrades.append(gradeAsInt)
}
}
print(transferGrades)
// Now that we have an array of numerical grades, we need to calculate the student's GPA. Create a new array called GPAValues that stores doubles.
var gpaValues: [Double] = [2.5, 3.0, 4.0, 3.12, 2.97, 2.27]
// Like with the letter conversion function and switch you created before, make a new function called calculateGPA that takes a double and returns a double. Inside your function, create another switch that does the following conversion. Grades below 60 earn zero grade points, grades in the 60s earn 1, 70s earn 2, 80s earn 3, and 90s and above earn 4.
func calculateGPA(gpaValue: Double) -> Double {
switch gpaValue {
case 0..<59:
return 0
case 60...69:
return 1
case 70...79:
return 2
case 80...89:
return 3
case 90..<100:
return 4
default:
return 0
}
}
// Loop through your convertedGrades array and append the grade point value to the GPAValues array. Because your calculateGPA function returns a value, you can use it just like a varialbe, so rather than calculate the grade points and then put that varialbe in your append statement, append the actual function. i.e. myArray.append(myFunction(rawValueToBeConverted))
for gpa in gpaValues {
gpaValues.append(calculateGPA(gpaValue: gpa))
}
// Finally, calculate the average GPA by looping through the GPA and using the += operator to add it to a variable called totalGradePoints. You may need to initialize the variable before using it in the loop. i.e. var initialized = Double()
var totalGradePoints = Double()
for gpa in gpaValues {
let averageGPA: Double = gpa += totalGradePoints
}
// Count the number of elements in the array (by using the count method, not your fingers) and store that number in a variable called numberOfGrades. Pay attention to creating your variables with the right types. Swift will tell you if you're doing it wrong.
var numberOfGrades: Int = gpaValues.count
// Divide the totalGradePoints by numberOfGrades to store in a variable called transferGPA.
var transferGPA: Double = Double(totalGradePoints) / Double(numberOfGrades)
// Using code, add one numerical grade and one letter grade to the transferGrades array that we started with (i.e. append the values rather than manualy writing them into the line at the beginning of this file) and check that your transferGPA value updates. You'll need to append the new grades on the line below the existing transferGrades array so that your changes ripple through the playground.
transferGrades.append(97.56)
transferGrades.append("B")
averageGPA must be define using the var keyword to make it mutable later on when summing up the values.
var averageGPA: Double = 0
for gpa in gpaValues {
averageGPA += gpa
}
averageGPA = averageGPA / Double(gpaValues.count)
Recall the average is calculated by summing up the score and dividing the number of scores.
Defining something with let means that the following will be a constant.
let answer: Int = 42
answer = 43 /* Illegal operation. Cannot mutate a constant */
Left side of mutating operator isn't mutable: 'gpa' is a 'let' constant
The problem is that gpa is a constant, you can't modify its value. And the "+=" operator means "increase gpa's value by totalGradePoints", it is trying to increase the value of gpa. What you probably mean to do is make averageGPA equal the sum of gpa and totalGradePoints. For that you would do this:
let averageGPA: Double = gpa + totalGradePoints
x is an object that holds an array called point.
x implements the subscript operator so you can do things, like x[i] to get the array's ith element (of type T, which is usually an Int or Double).
This is what I want to do:
x[0...2] = [0...2]
But I get an error that says ClosedInterval<T> is not convertible to Int/Double.
Edit1:
Here is my object x:
let x = Point<Double>(dimensions:3)
For kicks and giggles: define x as [1.0,2.0,0.0]
I can get the first n elements via x[0...2].
What I want to know is how to update x[0...2] to hold [0.0, 0.0.0.0] in one fell swoop. Intuitively, I would want to do x[0...2] = [0...2]. This does not work as can be seen in the answers. I want to update x without iteration (on my end) and by hiding the fact that x is not an array (even though it is not).
[0...2] is an array with one element which, at best, will be a Range<Int> from 0 through 2. You can't assign that to a slice containing, say, Ints.
x[0...2] on the other hand is (probably) a slice, and Sliceable only defines a get subscript, not a setter. So even if the types were more compatible - that is, if you tried x[0...2] = 0...2, which at least is attempting to replace a range within x with the values of a similarly-sized collection - it still wouldn't work.
edit: as #rintaro points out, Array does support a setter subscript for ranges – so if x were a range you could do x[0...2] = Slice(0...2) – but it has to be a slice you assign, so I'd still go with replaceRange.
If what you mean is you want to replace entries 0 through 2 with some values, what you want is replaceRange, as long as your collection conforms to RangeReplaceableCollection (which, for example, Array does):
var x = [0,1,2,3,4,5]
var y = [200,300,400]
x.replaceRange(2..<5, with: y)
// x is now [0,1,200,300,400,5]
Note, the replaced range and y don't have to be the same size, the collection will expand/contract as necessary.
Also, y doesn't have to an array, it can be any kind of collection (has to be a collection though, not a sequence). So the above code could have been written as:
var x = [0,1,2,3,4,5]
var y = lazy(2...4).map { $0 * 100 }
x.replaceRange(2..<5, with: y)
edit: so, per your edit, to in-place zero out an array of any size in one go, you can do:
var x = [1.0,2.0,0.0]
// range to replace is the whole array's range,
// Repeat just generates any given value n times
x.replaceRange(indices(x), with: Repeat(count: x.count, repeatedValue: 0.0))
Adjust the range (and count of replacing entries) accordingly if you want to just zero out a subrange.
Given your example Point class, here is how you could implement this behavior assuming it's backed by an array under the hood:
struct Point<T: FloatLiteralConvertible> {
private var _vals: [T]
init(dimensions: Int) {
_vals = Array(count: dimensions, repeatedValue: 0.0)
}
mutating func replaceRange
<C : CollectionType where C.Generator.Element == T>
(subRange: Range<Array<T>.Index>, with newElements: C) {
// just forwarding on the request - you could perhaps
// do some additional validation first to ensure dimensions
// aren't being altered...
_vals.replaceRange(subRange, with: newElements)
}
}
var x = Point<Double>(dimensions:3)
x.replaceRange(0...2, with: [1.1,2.2,3.3])
You need to implement subscript(InvervalType) to handle the case of multiple assignments like this. That isn't done for you automatically.