I need to use a for loop to create a 2d array. So far "+=" and .append have not yielded any results. Here is my code. Please excuse the rushed variable naming.
let firstThing = contentsOfFile!.componentsSeparatedByString("\n")
var secondThing: [AnyObject] = []
for i in firstThing {
let temp = i.componentsSeparatedByString("\"")
secondThing.append(temp)
}
The idea is that it takes the contents of a csv file, then separates the individual lines. It then tries to separate each of the lines by quotation marks. This is where the problem arises. I am successfully making the quotation separated array (stored in temp), however, I cannot make a collection of these in one array (i.e. a 2d array) using the for loop. The above code generates an error. Does anybody have the answer of how to construct this 2d array?
You can do this using higher order functions...
let twoDimensionalArray = contentsOfFile!.componentsSeparatedByString("\n").map{
$0.componentsSeparatedByString("\"")
}
The map function takes an array of items and maps each one to another type. In this I'm mapping the strings from the first array into an array pf strings and so creating a 2d array.
This will infer the type of array that is created so no need to put [[String]].
Here you go...
Related
How does Swift know the address of an element in an array of Any? I can’t find any explanation. For example:
var array: [Any] = [0, "1"]
print(array[1]) // print “1”
Usually, in other programming languages like C/C++, we can only declare an array of a specified type, therefore we can calculate the address of an element by: start + index * Element.size. How to calculate the address of an element of array with a specified index if we don't have a fixed size of elements in the array?
UPDATE:
Apparently I’m not expecting Swift to behave like C. We certainly know how to access an array in Swift. I’m wondering how Swift or other language implements accessing an array of heterogenous types.
Alejandro Alonso has answered this question in the official Swift forum. FYI:
https://forums.swift.org/t/how-does-swift-know-the-address-of-an-element-in-an-array-of-any/45415/3
Does anyone know here how to count amount of elements in all nested array of custom objects in Swift?
I.e. I have
[Comments] array which includes [Attachments] array. There may be 100 comments and 5 attachments in each of them. What is the most Swifty way to count all attachments in all comments? I tried few solutions like flatMap, map, compactMap, filter, reduce, but couldn't figure out how to achieve the desire result. The only one that worked for me was typical for in loop.
for comment in comments {
attachmentsCount += comment.attachments.count
}
Is there any better approach to achieve the same? Thanks
You can use reduce(_:_:) function of the Array to do that:
let attachementsCount = comments.reduce(0) { $0 + $1.attachments.count }
Here are two ways to do it based on using map
First with reduce
let count = comments.map(\.attachments.count).reduce(0, +)
And one variant using joined
let count = comments.map(\.attachments).joined().count
Is there any way to create multiple array dynamically as per count.
For example count is 10, then there will be 10 array created dynamically with name array1,array2,array3 ...
It is impossible unlike in PHP, Swift is not an interpreted language.
All what you need - to create array of arrays. Declaration:
var array: [[Any]]!
Initialization:
let i = 10
array = [[Any]](count: i, repeatedValue: [Any]())
Now you access for your arrays, not like array0, array1, but like array[0], array[1]. And there is no way to create truely custom dynamic name variables dynamically.
How to create an array in VTL and add contents to the array? Also how to retrieve the contents of the array by index?
According to Apache Velocity User Guide, right hand side of assignments can be of type
Variable reference
List item
String literal
Property reference
Method reference
Number literal
ArrayList
Map
You can create an empty list, which would satisfy all your needs for an array, in an Apache Velocity template with an expression like:
#set($foo = [])
or initialize values:
#set($foo = [42, "a string", 21, $myVar])
then, add elements using the Java add method:
$foo.add(53);
$foo.add("another string");
but beware, as the Java .add() method for the list type returns a boolean value, when you add an element to the list, Velocity will print, for instance, "true" or "false" based on the result of the "add" function.
A simple work around is assigning the result of the add function to a variable:
#set($bar = $foo.add(42))
You can access the elements of the list using index numbers:
<span>$foo[1]</span>
Expression above would show a span with the text "a string". However the safest way to access elements of a list is using foreach loops.
Creating an array is easy:
#set($array = [])
Putting an element into an array is also easy:
$array.add(23)
Getting an element from an array depends from your Velocity version.
In Velocity 1.6 you must use
$array.get($index)
Since Velocity 1.7 you can use the classic form:
$array[$index]
I haven't created an array in VTL but passed arrays to VTL context and used them. In VTL, you can not retrieve array contents by index, you only use foreach, as example this code is copied from my Dynamic SQL generation VTL Script:
#foreach( $col in $Columns ) SUM($col.DBColumn) AS ''$col.Name''#if($velocityCount!=$Columns.Count), #end #end
For this reason, we also can not have 2D arrays. When I needed an array to store 2 objects in a row, I used the workaround of defining a new class, and putting objects of that class in the single dimensional array.
I am collecting the values for a specific column from a named_scope as follows:
a = survey_job.survey_responses.collect(&:base_pay)
This gives me a numeric array for example (1,2,3,4,5). I can then pass this array into various functions I have created to retrieve the mean, median, standard deviation of the number set. This all works fine however I now need to start combining multiple columns of data to carry out the same types of calculation.
I need to collect the details of perhaps three fields as follows:
survey_job.survey_responses.collect(&:base_pay)
survey_job.survey_responses.collect(&:bonus_pay)
survey_job.survey_responses.collect(&:overtime_pay)
This will give me 3 arrays. I then need to combine these into a single array by adding each of the matching values together - i.e. add the first result from each array, the second result from each array and so on so I have an array of the totals.
How do I create a method which will collect all of this data together and how do I call it from the view template?
Really appreciate any help on this one...
Thanks
Simon
s = survey_job.survey_responses
pay = s.collect(&:base_pay).zip(s.collect(&:bonus_pay), s.collect(&:overtime_pay))
pay.map{|i| i.compact.inject(&:+) }
Do that, but with meaningful variable names and I think it will work.
Define a normal method in app/helpers/_helper.rb and it will work in the view
Edit: now it works if they contain nil or are of different sizes (as long as the longest array is the one on which zip is called.
Here's a method that will combine an arbitrary number of arrays by taking the sum at each index. It'll allow each array to be of different length, too.
def combine(*arrays)
# Get the length of the largest array, that'll be the number of iterations needed
maxlen = arrays.map(&:length).max
out = []
maxlen.times do |i|
# Push the sum of all array elements at a given index to the result array
out.push( arrays.map{|a| a[i]}.inject(0) { |memo, value| memo += value.to_i } )
end
out
end
Then, in the controller, you could do
base_pay = survey_job.survey_responses.collect(&:base_pay)
bonus_pay = survey_job.survey_responses.collect(&:bonus_pay)
overtime_pay = survey_job.survey_responses.collect(&:overtime_pay)
#total_pay = combine(base_pay, bonus_pay, overtime_pay)
And then refer to #total_pay as needed in your view.