I created a data structure based on a dictionary of words. The purpose is to link each word to all other words made up of the same letters plus one.
Example: table -> ablate, cablet, tabled, gablet, albeit, albite, etc.
For this I built a data model made of three entities: Word, Draw, Link.
A Draw is a set of letters corresponding to a Word and sorted in alphabetic order, like : HOUSE -> EHOSU. A Link is a letter that you add to a Draw to get another Draw.
So my data model looks like this:
And here is how I implemented it in Xcode:
Entity Word
(let's forget the attribute optComp that plays no role here)
Entity Draw
Entity Link
I am populating the data in two steps:
first I read a list of words from a .txt source and I populate the Word entity and at the same time the Draw entity with the corresponding relationship (function loadDic())
This first step apparently works fine. I can easily find all anagrams of any word with something like word.sort.word.spelling
I read through the Draw entity. For each draw I seek all existing +1 draws considering each letter of the alphabet. If there are, I create a Link and add the relationships (function createLinks())
Here is where something goes wrong. If the Link's and the relationship Draw.plus seem to be correctly created, the other relationship Link.gives is only partially populated, say 50%.
Moreover, I tried to apply an additional routine (updateLinks()) , focusing only on Link's with an empty Link.gives relationship and updating them. But again, only 50% of the nil relationships appear to be populated.
I could not find out why those relationships are not properly populated. If someone can help me out I would be grateful.
Here is the code:
LoadDic() function (OK) :
func loadDic() {
print("Loading dictionary...")
dataAlreadyLoaded.toggle()
guard let url = Bundle.main.url(forResource: INPUT_FILE, withExtension: "txt") else {
fatalError("\(INPUT_FILE).txt not found")
}
if let dico = try? String(contentsOf: url, encoding: String.Encoding.utf8 ) {
let lines = dico.split(separator: "\r\n")
for line in lines {
let lineArray = line.split(separator: " ")
print("\(lineArray[0])") // word
let wordSorted = String(lineArray[0].sorted())
let draw = getDraw(drawLetters: wordSorted) ?? addDraw(drawLetters: wordSorted) // look if draw already exists, otherwise create new one.
let wordItem = Word(context: viewContext) // create word entry with to-one-relationship to draw
wordItem.spelling = String(lineArray[0])
wordItem.optComp = (Int(String(lineArray[1])) == 1)
wordItem.sort = draw
do {
try viewContext.save()
} catch {
print("Errort saving ods9: \(error)")
}
}
}
print("Ods Chargé")
}
func addDraw(drawLetters: String) -> Draw {
let newDraw = Draw(context: viewContext)
newDraw.draw = drawLetters
return(newDraw)
}
func getDraw(drawLetters: String) -> Draw? {
let request: NSFetchRequest<Draw> = Draw.fetchRequest()
request.entity = Draw.entity()
request.predicate = NSPredicate(format: "draw == %@", drawLetters)
do {
let drw = try viewContext.fetch(request)
return drw.isEmpty ? nil : drw[0]
} catch {
print("Erreur recherche Tirage")
return nil
}
}
createLinks() function (NOK):
func createLinks() {
var erreur = " fetch request <Draw>"
let request: NSFetchRequest<Draw> = Draw.fetchRequest()
request.entity = Draw.entity()
request.predicate = NSPredicate(value: true)
print("Building relationships...")
do {
let draws = try viewContext.fetch(request)
count = draws.count
for draw in draws {
print("\(count) - \(draw.draw!)")
linkTable.removeAll()
for letter in ALPHABET {
print(letter)
let drawLettersPlus = String((draw.draw! + String(letter)).sorted()) // draw with one more letter
if let drawPlus = draws.first(where: { $0.draw == drawLettersPlus }) { // look for Draw entity that matches augmented draw
let linkItem = Link(context: viewContext) // if found, create new link based on letter with relationship to augmented draw
linkItem.letter = String(letter)
linkItem.gives = drawPlus
erreur = " saving \(draw.draw!) + \(letter)"
try viewContext.save()
linkTable.append(linkItem) // saves link to populate the one-to-many relationship of the initial draw, once the alphabet is through
}
}
let drawUpdate = draw as NSManagedObject // populate the one-to-many relationship of the initial draw
let linkSet = Set(linkTable) as NSSet
drawUpdate.setValue(linkSet, forKey: "plus")
erreur = " saving \(draw.draw!) links plus"
try viewContext.save()
count -= 1 // next draw
}
} catch {
print("Error " + erreur)
}
print("Graph completed")
}
updateLinks function (NOK):
func updateLinks() {
var erreur = "fetch request <Link>"
let request: NSFetchRequest<Link> = Link.fetchRequest()
request.entity = Link.entity()
print("Running patch...")
do {
request.predicate = NSPredicate(format: "gives == nil")
let links = try viewContext.fetch(request)
for link in links {
let baseDraw = link.back!.draw!
print("\(baseDraw) \(link.letter!)")
let augmDrawLetters = String((baseDraw + link.letter!).sorted())
if let augmDraw = getDraw(drawLetters: augmDrawLetters) {
viewContext.perform {
let updateLink = link as NSManagedObject
updateLink.setValue(augmDraw, forKey: "gives")
erreur = " saving \(augmDraw.draw!) \(link.letter!)"
do {
try viewContext.save()
} catch {
print("Erreur mise à jour lien")
}
}
}
}
} catch {
print("Error " + erreur)
}
}
RESULT
And this is the output showing the content of the Draw entity with relationships after createLinks() is applied:
And here after updateLinks() is applied :
Post
Replies
Boosts
Views
Activity
Example:
I have a state var curHighScore declared in ContentView.
I select it, right click and select "Find Selected Symbol in Workspace"
The result is : 1 resul in 1 file, i.e. the line of declaration of the var
But obviously, the same var is used at line #102:
How come this occurence is not found by the search command.
Such happens every now and then. Is there something I am missing ? What is causing this ? Thanks for your help.
Hi,
My app has been on the store for a few months now with a few updates.
Now I plan a major update that will affect the structure of core data itself (key attribute replaced by relationship). I see no other way than asking the users to delete and reinstall the app to reset all data and start it as new.
In a previous update I provided users the possibility to backup their data in a file so they can restore it with the future release.
Is there a better way than using the "What's new in this version" section to pass the message to the users ?
When I run my app in debug mode, whenever a time consuming task is run (like a core data fetch request) there is a time indication appearing on top of the view. I am unable to find the meaning of this and how it is named.
It looks like:
"appName NNNN ms"
(it is not caught by the screen shot)
Can someone tell if it is possible to get rid of it and how ? Thanks for your help !
I have a View with a few TextViews, which look almost fine except the background color of the textviews that is white, where I would like it to be blue:
Here the code:
VStack {
HStack {
TextField("mot", text:$tfMot)
.dynamicTypeSize(.xLarge)
.disabled(true)
.background(Color("fondbleu"))
TextField("orthoAlt", text:$tfOrthoAlt, axis: .vertical)
.dynamicTypeSize(.small)
.background(Color("fondbleu"))
.disabled(true)
}
TextField("Définition", text:$tfDefinition, axis: .vertical)
.background(Color("fondbleu"))
.disabled(true)
TextField("Anagrammes", text:$tfAna, axis: .vertical)
.background(Color("fondbleu"))
.disabled(true)
TextField("Extensions +1", text: $tfExt, axis: .vertical)
.background(Color("fondbleu"))
.disabled(true)
}
As one can see, the modifier:
.background(Color("fondbleu"))
has no effect.
I found out that the background color would change only if I ad the modifier:
.textFieldStyle(.plain)
But then, apparently all the attributes of the default text field style are lost and the text is stuck in the upper right corner of the field:
My problem now is how to get the text back in the vertical center of the field.
By the way, I tried to fix it using the attributes inspector panel but this one is frozen:
Any one can help me out ?
I have set a core data structure based on two entities :
first entity is "Mot" (Word) with one String attribute "graphie" (spelling) and one ToOne relationship "definition" with the second entity.
second entity is "Definition" that has one String attribute "enonce" (statement) and on ToMany relationship "mot" with entity Mot.
One word can have several spellings but only one definition.
I managed to load several rows of data and now, when I select one word I want to display all the spellings, which means all "Mot" that have the same definition.
In my content view I have a List based on a request:
@Environment(\.managedObjectContext) private var viewContext
@FetchRequest(entity: Mot.entity(), sortDescriptors: [NSSortDescriptor(key: "graphie", ascending: true)])
private var mots: FetchedResults<Mot>
var body: some View {
NavigationView {
...
List {
ForEach(mots) { (mot: Mot) in
HStack {
Text(mot.graphie ?? "Non trouvé")
Spacer()
Text(mot.definition!.enonce ?? "Non trouvé")
}
.onTapGesture {
motAffiche = mot
tfMot = mot.graphie ?? "Not found"
tfDefinition = mot.definition?.enonce ?? "Not found"
tfOrthoAlt = returnOrthoAlt(mot: mot)
}
}
}
the function returnOrthoAlt(mot) is supposed to return a string with all spellings separated by commas.
What is working for the moment, but not satisfactory is the following code for that function
private func returnOrthoAlt(mot: Mot) -> String {
var ort = [String]()
for elem in mots {
if elem.definition!.enonce! == mot.definition!.enonce! && elem != mot {
ort.append(elem.graphie!)
let defObjId = elem.definition!.objectID.uriRepresentation()
print("\(elem.graphie!) def: \(elem.definition!.enonce!) \(defObjId) ")
}
}
return if !ort.isEmpty { ort.joined(separator: ", ")} else {""}
}:
I am going through the table 'mots' of FetchedResults to find those that have the same definition as the current 'mot'. What I find not satisfactory is that I am comparing the 'mot.definition.enonce' of each Mot, which is not supposed to be unique, instead of 'mot.definition' directly, which did not work. The objects 'mot.definition' are obviously not equal (neither with == nor with === operators).
Also I tried to retrieve the reverse relation directly with 'mot.definition.mot' but that returned a NSSet which, converted to a set seems to contain only one object, that is 'mot' itself.
One possibility of course, would be to ad a unique Id to the entity 'Definition' but I seem to understand that this is not the recommended practice, the more so as swift does not provide system generated id.
What do I miss in the core data concept ? Can someone help me out ?