How to sort a dict in genie - vala

Update Solved the compiling error, now the only problem with the code is how to sort the dict alphabetically for pretty printing.
I am refactoring an argument parser from python into Genie, however I found myself stuck in how to sort the items form a dict before appending them to a list.
In python it is as simple as:
lines.append("Options:")
if len(self.options):
for name, option in sorted(self.options.items()):
lines.append(" %s: %s" % (name, option.values))
else:
lines.append(" [none]")
self.options is declared as self.options = {}
Now how can print the contents of the dict, but sorted?
Here is the code where I am stuck:
def ListOptions()
var lines = new list of string
lines.add("Options:")
if _options.size != 0
for name in _options.keys
lines.add(" %s: %s" % (name, _options.values))
else
lines.add(" [none]")
ListOptions is a method within a class, and I declared _options as _options:new dict of string, string
There is no compiling error in that section of the code anymore. My question is how to sort the elements of the dict before adding them to the list lines?

A dict of is in reality a Gee.HashMap of K, V, so you can look up what type the keys property is.
keys is of type Gee.Set of G which doesn't have a sort method.
It does however derive from Gee.Collection of G which we can use to make a new temporary list of string (which is Gee.ArrayList under the hood and does have a sort method).
I have put this into a sort_string_collection function (which could even be Generic, since it's not specific to strings, but I didn't bother because it's not easily possible with Genie at the moment).
With added test code, to make it a MCVE, the result looks like this:
[indent=4]
def sorted_string_collection (collection: Gee.Collection of string): Gee.Iterable of string
var l = new list of string
l.add_all (collection);
l.sort ()
return l;
def list_options (_options: dict of string, string): list of string
var lines = new list of string
lines.add("Options:")
if _options.size != 0
for name in sorted_string_collection (_options.keys)
lines.add(#" $name: $(_options[name])")
else
lines.add(" [none]")
return lines
init
var opts = new dict of string, string
opts["z"] = "23"
opts["abc"] = "42"
opts["pi"] = "3.141"
var l = list_options (opts)
for var s in l
print (s)
Or even more minimalistic (if we ever get to use stackoverflow Documentation for Genie, this would be a good example):
[indent=4]
def sorted_string_collection (collection: Gee.Collection of string): Gee.Iterable of string
var l = new list of string
l.add_all (collection);
l.sort ()
return l;
init
var dic = new dict of string, string
dic["z"] = "23"
dic["abc"] = "42"
dic["pi"] = "3.141"
for k in sorted_string_collection (dic.keys)
print (#"$k: $(dic[k])")

Based on Thomas and Jens comments, one can also use TreeMap. Here is how it would look:
[indent=4]
uses
Gee
init
var dic = new TreeMap of string, string
dic["z"] = "23"
dic["abc"] = "42"
dic["pi"] = "3.141"
for k in dic.ascending_keys
print (#"$k: $(dic[k])")

Related

Confused about static dictionary in a type, in F#

With this type:
type A =
{
S: string
}
static member private l = Dictionary<string, A>()
static member add s = A.l.[s] <- { S=s }
static member list () = l.Values
if I do:
A.add "hello"
A.add "world"
I'd expect A.list() to return something since the dictionary is static, but it returns an empty list. Why is that?
To clarify what I'm trying to do: I'd like to have the ability to register the objects of type A into a static dictionary that is attached to the type itself as it would make the object repository 'self contained' in the type, in a way.
Your l is not a field, but a property with a getter.
A "property", contrary to appearances, is not a memory cell with some value in it. A "property" is a pair of get+set functions. Just functions, that's all. No memory cell.
So what you made yourself is a property with a getter (without a setter), and all that getter does is create a new Dictionary and return it.
This means, every time you access A.l, you get yourself a new, fresh dictionary. Because l is a function, not a memory cell.
Now, in order to make a memory cell (aka "field"), one would ordinarily use static member val, like so:
static member val private l = Dictionary<string, A>()
Unfortunately, in this particular case this doesn't work, because static fields are not permitted on F# records and unions. They work fine on actual classes, but not on F# types.
So instead what I would recommend is to put those functions in a module rather than making them static methods:
type A = { S: string }
module A =
let private l = Dictionary<string, A>()
let add s = l.[s] <- { S=s }
let list () = l.Values
(and just in general: try to use fewer classes and more modules and functions; they're more idiomatic in F# and lead to fewer problems in general)
Now this works as expected:
> A.add "hello";;
val it : unit = ()
> A.add "world";;
val it : unit = ()
> A.list();;
val it : Dictionary`2.ValueCollection<string,A> =
seq [{ S = "hello" }; { S = "world" }]

F# Adding value to map result in KeyNotFoundException

type bytesLookup = Map<byte,int list>
type lookupList = bytesLookup list
let maps:bytesLookup = Map.empty
let printArg arg = printfn(Printf.TextWriterFormat<unit>(arg))
let array1 = [|byte(0x02);byte(0xB1);byte(0xA3);byte(0x02);byte(0x18);byte(0x2F)|]
let InitializeNew(maps:bytesLookup,element,index) =
maps.Add(element,List.empty<int>)(*KeyNotFoundException*)
maps.[element]
let MapArray (arr:byte[],maps:bytesLookup ) =
for i in 0..arr.Length do
match maps.TryFind(arr.[i]) with
| Some(e) -> i::e
| None -> InitializeNew(maps,arr.[i],i)
MapArray(array1,maps);
printArg( maps.Count.ToString())
Exception
System.Collections.Generic.KeyNotFoundException: The given key was not
present in the dictionary. at
Microsoft.FSharp.Collections.MapTreeModule.find[TValue,a](IComparer1
comparer, TValue k, MapTree2 m) at
Microsoft.FSharp.Collections.FSharpMap2.get_Item(TKey key) at
FSI_0012.MapArray(Byte[] arr, FSharpMap2 maps) in Script1.fsx:line 16
at .$FSI_0012.main#() in Script1.fsx:line 20
In the function I'm trying to initialize a new element in the map with a list of int. I also try to push a new int value into the list at the same time.
What am I doing wrong?
F# Map is an immutable data structure, the Add method doesn't modify the existing data structure, it returns a new Map with the additions you've requested.
Observe:
let ex1 =
let maps = Map.empty<byte, int list>
maps.Add(1uy, [1]) // compiler warning here!
maps.[1uy]
Two things about this code:
It throws System.Collections.Generic.KeyNotFoundException when you run it
It gives you a compiler warning that the line maps.Add... should have type unit but actually has type Map<byte,int list>. Don't ignore the warning!
Now try this:
let ex2 =
let maps = Map.empty<byte, int list>
let maps2 = maps.Add(1uy, [1])
maps2.[1uy]
No warning. No exception. Code works as expected, returning the value [1].

Turn a string into a variable

Hello I have a for in loop where elements is the variable being changed and in this case "elements" is a string but there is a corresponding variable out side of the for in loop that has the same name as the string called elements. So what I mean is out side there is a Var time = [some,text,words] and theres a for in loop that calls a STRING named "time" and I would like to know how to convert the string in the for in loop into the variable by some how taking off the "'s (not that simple I know) without specifically saying "time"(the variable) but instead converting the "elements"(which is the string 'time') string into the variable. I hope I was clear enough if I'm not making sense I'll try again.
You cannot refer to local variables dynamically by their names in Swift. This would break a lot of compiler optimizations as well as type safety if you could.
You can refer to object properties by their names if the class conforms to key-value coding. For example:
class X : NSObject {
let time = ["some", "text", "words"]
func readWordsFromProp(name: String) -> String {
guard let list = self.valueForKey(name) as? [String] else {
return ""
}
var result = ""
for word in list {
result += word
}
return result
}
}
let x = X()
print(x.readWordsFromProp("time"))
In general, there are better ways to do things in Swift using closures that don't rely on fragile name-matching. But KVC can be a very powerful tool

Swift - How to get the index of an array that has an initializer?

I am making an IOS app and I use swift. I have an array that I need in order to retrieve data from my CoreData database.
var myList : Array<AnyObject> = []
This "myList" array has an item called "Monday". I want to get the index of this item. I tried to use this to get the index, but it doesn't work.
find(daysOfWeek, "c")!
It gives me an error 'Genetic Paramater cannot be bound to non-#object protocol 'AnyObject''
This find method works fine for normal arrays like this:
var daysOfWeek = ["Monday", "Tuesday"]
How can I get the index of an item for my myList array?
As the error states, find can't work with AnyObject; so although this won't work:
var myList : Array<AnyObject> = []
find(myList, "c")
this will:
var myList : Array<String> = []
find(myList, "c")
Since you're searching for a string, making myList into an array of Strings should be sufficient.
var shoppingList:Array = ["Chocolate Spread", "Cheese", "Butter"]
var indexOfObject = 0
for var index = 0; index < shoppingList.count ; index++ {
if "Butter" == shoppingList[index] {
indexOfObject = index
}
}
println("Butter index is \(indexOfObject)")
I hope this ll help you to find the index of the object.. I don't there is any function to get index directly bt now i use like above only..
In any case, find requires a type that conforms to Equatable (i.e. has ==). == is not defined on AnyObject (there is no general definition of value equality on objects). However, == is defined on NSObject:
import Foundation
var myList : [NSObject] = []
find(myList, "c")

Syntax explanation: square brackets in Swift

I'm studying Swift and got confusing with following syntax:
var treasures: [Treasure] = []
Treasure is custom class, declared as follow:
class Treasure: NSObject { }
In Objective-C square brackets mean method, but what do they mean in Swift?
Ok, this is the meaning of
var treasures: [Treasure] = []
var: you are declaring a variable
treasures: the name of your variable
[Treasure]: the type of your variable, in this case the type is Array of Treasure, the compiler will allow you to insert only object of type Treasure in your Array
[]: the actual object (Array) referenced by your variable, in this case an empty Array.
E.g. if you want the Array to hold 2 elements you can write
var treasures: [Treasure] = [Treasure(), Treasure()]
Hope this helps.
Update:
My example can also be written this way
var treasures = [Treasure(), Treasure()]
Infact thanks to the Type Inference the compiler can deduce the type of the variable treasures looking at the type of the assigned value.
[Treasure] is just a syntax sugar for Array<Treasure>.
The same way [String:Treasure] is just a syntax sugar for Dictionary<String,Treasure>.
[] is just an empty array of the type you defined. The same way [:] is an empty dictionary.
When it comes to Swift and square brackets, the rules are simple. They are used only in two situations:
1) working with Array and Dictionary types:
let vectors : [[Int]] = [[1,2,3],[4,5,6]]
let birthBook : [Int:[String]] = [1987:["John","William"], 1990: ["Mary"]]
2) for subscripting objects that support subscripting:
class RouteMapper {
private var routeMap : [String:String] = [:]
subscript(endpoint: String) -> String {
get {
if let route = routeMap[endpoint] {
return route
}
return "/"
}
set(newValue) {
routeMap[endpoint] = newValue
}
}
}
let routeMapper = RouteMapper()
routeMapper["users"] = "/v1/confirmed/users"
let url = routeMapper["admins"]
Since [ and ] are not allowed in custom operators, these are the only usages for now.

Resources