I have a requirement to read a csv file and generate several different projections of the data from save to files. I'm using CsvProvider to read the file and then map the data into other CsvProviders which I save to disk. Currently I have seperate save functions to save each of these projections. I'm wondering if I could create a generic saveCsv function like this?
let saveCsv<'a when 'a :> CsvProvider> (csvType:'a) fileName data =
let csv = new csvType(data)
csv.Save(fileName)
I can't seem to get the type constraint correct and also how do I new up a instance of the csvtype?
Related
I'm working on the data model for an app I'm building that will use CoreData. As part of that process, the app includes a function that will iterate through a series of MP3 files to populate the database.
The data model at the moment is:
var metadataArray = [(fileName: String, title: String, artist: String,
duration: String, fileExtension: String)]()
Note that in order for the app to later access those files, I'm storing the file name and the file extension. Since the path to the app's Documents folder isn't known at build time, my thought was to include code that programmatically locates the Documents folder. Then, when it's time to access a file, use the stub path to the Documents folder and tack on the filename String and fileExtension String using .appendPathComponent() to generate a URL from the three components.
My question feels kind of esoteric, but it seems like the right time to ask it:
Q: Swift provides a method to assemble URLs from strings, but in the data model declaration, is there any special data Type that's more appropriate for storing file names and file extensions than just plain Strings?
I'm guessing the answer is no -- that Strings are fine, given all the methods Swift provides to assemble full URLs from Strings. But since Swift allows you to declare a full URL as a data type, I thought it was worth asking if there's some sort of a data type more suitable for components of a URL.
Thanks in advance!
I am developing an iOS app using Swift (still new to swift).
I have a databank saved as a csv file and that is primarily the core of the app. The databank contains a table divided into a list of all countries (rows) each with many attributes/descriptors (the columns). Really there is no relationship between the countries.
What I would like to do is to be able to display this information for the (selected) country in my app. As well as do other things like search/filtering/sorting based on the attribute/property chosen.
The databank might be updated in the future with the release of app updates but other than that I think I want it to be read once from the csv file and then the app uses that data.
Am I right in thinking that the best way to implement this is by using Core Data with ONE entity (country) with the different attributes? So then all I have to do is read the csv file once and persistent store all the data and use it from there.
Or is Core Data not the best implementation? Shall I just create a class Country with the many attributes and use that? But then that means the app will have to read the csv every time it opens and save the data to arrays etc if I wanted to filter or sort?
So I guess in summary my questions are:
1. Use Core Data or not? If not then what do you think the best implementation is?
2. If using Core Data, am I just creating ONE entity (so no relationships etc).
What would see this as is that you would want to load this into your database of choice; Thus CoreData or SQLite or even Realm would work.
In case you don't have the data available for any of them yet and you want to load them in using swift this is a parser that I wrote for a similar situation where CSV is my raw datasource that I need to parse:
if let listFile = try? String(contentsOfFile: path) {
let lines = listFile.components(separatedBy: "\n")
// NOTE: There is also a CSV format that uses ',' as a separator
// So verify if yours uses ';' or ','
let rows: [[String: String]] = lines.flatMap() {
(item) -> [String: String]? in
let components = item.components(separatedBy: ";")
if components.count != 3 {
return nil
}
// Modify this part to parse the X amount of columns
// you have in your countries.csv
let dict = [
"identity": components[0],
"description": components[1].lowercased(),
"points": components[2]
]
return dict
}
}
}
Then after you have the data in an [[String: String]] format you could parse that row by row and insert them into the database you chose to use.
I believe in Swift4 it should be possible to use the new Codable protocols in order to achieve a result that would look a lot cleaner; but I have not written an Encoder/Decoder for CSV files ( yet ) that would allow you to do this. If there is one available I'll post it here.
There is also a CSV parser available on github here:
SwiftCSV
I have never used it, but who knows; might be helpful to you.
My project handles data that is stored in a key value based NoSQL database.The value part is stored as byte stream.I want a type provider to read my data according to the schema of the byte stream.The schema of the data is represented as json schema. Can I use Json type provider to read this data? If no then what can be the solution to my problem?
If your DB stores the JSON as a bytestream, simply decode it through System.Text.Encoding.UTF8.GetString (replace UTF8 with the appropriate encoding if necessary) in order to get the JSON as a regular string.
Then, you can use the JSON type provider on that stream like on any other stream, as long as you provide a compile-time sample for the type provider to use. A schema doesn't work.
In other words, you need to extract a fully representative sample of your database's JSON contents, then declare the provided types using that sample, either as a string directly embedded in the code, or as a file URI that your development machine can access.
As long as the sample matches the actual structure of your database, it will work at run-time.
// embedded in the code
type Simple1 = JsonProvider<""" { "name":"John", "age":94 } """>
// referenced
type Simple2 = JsonProvider<#"C:\MyProjectFolder\sample.json">
I understand how to retrieve data from an XML source using type providers. However, I need to then modify a particular part of the XML and save it to disk. I have tried assigning a value to the node using <- but the property is read-only.
For example:
let doc = MyXml.load fileName
doc.ItemId.Id <- "newId" // doesn't work
doc |> saveXml
There is a similar question for JSON where the suggestion is to create a new object, but this is specifically for XML.
While researching my question I found that you can use the .XElement accessor to get a reference to a mutable XElement object. Thus a solution is:
let doc = MyXml.load fileName
doc.ItemId.XElement.Element(XName.Get "Id").Value <- "newId" // tada
doc.XDocument.Save(...)
Note that you have to use the .XElement accessor on the parent if you're modifying a leaf node. This is because the leaf node's type is a primitive and doesn't have an .XElement accessor of its own. A slight shame, but I suppose it makes life easier on the other side when you want read-only access to the value.
How can I convert any record type to a single String and back? Perhaps load the record into a stream and read it as a String? The records I'm using won't have any special types included - they're just using simple things like String, Integer, PChar, DWORD, and Array of [String], etc. and nothing like classes or functions.
This string will further be saved into various places, such as a flat text file, database record, sent over the network, etc. The string contents may be transferred by other means between each of these, such as copying the string from a text file and saving it to a database record. The general idea is that the string will be compatible enough to save anywhere, move it around, and load it back in to its original state. I do understand I need to be able to recognize what type of record it is and assign it accordingly, and that part I don't need help with.
You can serialize your record using the RTTI, from here you can use XML, JSON or other format to persist the record data.
If you don't want write your own method to serialize the records try these alternatives.
superobject (using the TSuperRttiContext class you can serialize a record to JSON)
TKBDynamic
SynCommons unit from Synopse.
XmlSerial unit (Object and Record Serialization and De-serialization to XML) from Robert Love