Custom Sequence for Swift Dictionary

Custom sequence for Swift Dictionary

If I'm understanding correctly, how about just forwarding on the generate?

func generate() -> DictionaryGenerator<String, STCQuestion> {
return questionDict.generate()
}

(You don't need to implement GeneratorType, just SequenceType should do. It's generate() itself that returns a GeneratorType, and that's what has to implement next(), which the existing generate() implementation in Dictionary already does for you.)

Full worked example based on your code:

// Playground - noun: a place where people can play

import Foundation

class STCQuestion {
let foo: String
init(_ foo: String) {
self.foo = foo
}
}

class STCQuestionList : SequenceType {

private var questionDict: [String : STCQuestion] = [ : ];

subscript(key : String?) -> STCQuestion? {
get {
if key != nil {
return self.questionDict[key!];
}
return nil;
}
set(newValue) {
if key != nil {
self.questionDict[key!] = newValue;
}
}
}

func generate() -> DictionaryGenerator<String, STCQuestion> {
return questionDict.generate()
}
}

var list = STCQuestionList()
list["test"] = STCQuestion("blah")
list["another"] = STCQuestion("wibble")
list["third"] = STCQuestion("doodah")

for (key, value) in list {
println("Key: \(key) Foo: \(value.foo)")
}

// Output:
// Key: test Foo: blah
// Key: another Foo: wibble
// Key: third Foo: doodah

Write a Generator to custom dictionary class in Swift with Generics

Got the answer,
you will have to add following code extending orderedDictionary with SequenceType and adding a Generate method

/// extension class

extension OrderedDictionary: SequenceType {

/// Creates a generator for each (key, value)
func generate() -> GeneratorOf<(Tk , Tv)> {
var index = 0
return GeneratorOf<(Tk , Tv)> {
if index < self.count {
let key = self.keys[index]
let value = self[index]
index++
return (key, value!)
} else {
index = 0
return nil
}
}
}
}

How to maintain the order of the data in Dictionary in Swift?

Short answer:

You can not maintain order in the Dictionary.

Long answer:

Apple says:

Dictionaries are unordered collections of key-value associations.

Please refer this

To maintain the order you need to use the Array or create sorted Array(Ascending, Descending or by using specific key) from the Dictionary and use it.

Thank you.

Sequence extension that works on Arrays, Sets and Dictionaries in Swift

As isMultiple(of:) belongs to all integer types a generic version must be constrained to BinaryInteger

extension Sequence where Element : BinaryInteger {
var isAllEven : Bool {
allSatisfy {$0.isMultiple(of: 2)}
}
}

But this cannot cover Dictionary, because although Dictionary conforms to Sequence the Element type is different.

You could write a second extension of Sequence which matches the Dictionary tuple type

extension Sequence where Element == (key:String, value:Int) {
var isAllEven : Bool {
allSatisfy {$0.value.isMultiple(of:2)}
}
}

but this considers only String keys and Int values

A more generic way is to extend Dictionary directly

extension Dictionary where Value : BinaryInteger {
var isAllEven : Bool {
allSatisfy {$0.value.isMultiple(of: 2)}
}
}

Swift: Sort dictionary by keys with custom order

It seems to me your main challenge is a way to sort your season strings. The fact that you want to sort an array of dictionary keys is incidental.

I would suggest creating a global function valueForSeason that takes a string as input. It would return a double representing the season: The starting year value as the integer part, plus 0.0 for summer and 0.5 for winter. Return 0.0 for a malformed season string so those float to the top.

Then you could pull out your dictionary keys into an array and sort them by valueForSeason:

var keys =  dict.keys
keys.sort()
{
$0.valueForSeason() < $1.valueForSeason()
}

Note that you've got a Y2K bug lurking in your data format that you really can't fix. You're using 2 character years, and 99 most likely represents 1999, but it would sort after 14. You can play games like assuming dates after '50 are in the 1900's and dates before '50 are in the 2000's, but that approach is error-prone. You'd be much better off changing your string format to " YYYY" (e.g. "Summer 2014" and "Winter 2014/2015")

Preserve order of dictionary items as declared in Swift?

In your case an array of custom objects might be more appropriate.
Here is a simple example that should help to get you started:

struct Unit : Printable {
let name: String
let factor: Double

// println() should print just the unit name:
var description: String { return name }
}

let units = [
Unit(name: "kg", factor: 1000.0),
Unit(name: "g", factor: 1.0),
Unit(name: "mg", factor: 0.001),
Unit(name: "lb", factor: 453.592292),
Unit(name: "oz", factor: 28.349523)
]

println(units) // [kg, g, mg, lb, oz]

(I am not sure if the non-metric unit factors are correct :)

How do I expose a Swift Dictionary as a typed sequence of key-value pairs?

Probably someone comes up with a more elegant solution, but this works:

class Foo<K : Hashable, V> {
var dict: [K:V] = [:]

func asSequence() -> SequenceOf<(K, V)> {
return SequenceOf(dict)
}
}

... I could probably figure out how to wrap dict in something that conforms to SequenceType ...

That is exactly what SequenceOf<> does for you. From its API
documentation:

/// A type-erased sequence.
///
/// Forwards operations to an arbitrary underlying sequence with the
/// same `Element` type, hiding the specifics of the underlying
/// sequence type.

Create a Swift Dictionary subclass?

Swift dictionaries are structs, not classes, so they cannot be subclassed. Ideally, the methods you're working with would be declared to take an appropriately constrained generic CollectionType (or ExtensibleCollectionType, or SequenceType, depending on the situation), rather than specifically a Dictionary.

If that doesn't work for you for whatever reason, you could subclass NSDictionary instead.

(edit) and as Antonio points out, you can do extension Dictionary { … } to add things to the Dictionary struct, which can replace subclassing in some cases.

Extension for sequences of dictionaries where the values are Equatable

A [String: Equatable] is a mapping of strings to any Equatable type. There is no promise that each value be the same equatable type. That said, it's not actually possible to create such a dictionary (since Equatable has an associated type), so this extension cannot apply to any actual type in Swift. (The fact that you don't receive an error here is IMO a bug in the compiler.)

The feature you'd need to make this work is SE-0142, which is accepted, but not implemented. You currently cannot constrain an extension based on type constraints this way.

There are many ways to achieve what you're trying to do. One straightforward way is to pass your equality function:

extension Sequence {
public func removeDoubles(with equal: (Iterator.Element, Iterator.Element) -> Bool) -> [Iterator.Element] {
var noDoubles: [Iterator.Element] = []
for item in self {
if !noDoubles.contains(where: { equal($0, item) }) {
noDoubles.append(item)
}
}
return noDoubles
}
}

let noDupes = dict.removeDoubles(with: { $0["name"] == $1["name"] })

This is slightly different than your code in how it behaves when name is missing, but slight tweaks could get what you want.

That said, the need for this strongly suggests an incorrect data model. If you have this sequence of dictionaries, and you're trying to build an extension on that, you almost certainly meant to have a sequence of structs. Then this becomes more straightforward. The point of a dictionary is an arbitrary mapping of keys to values. If you have a small set of known keys that are legal, that's really a struct.

How to use compact map on custom type?

You can use .reduce(into:_:):

let dictionary = all.reduce(into: [:]) { dict, elem in
dict[elem.key] = elem.value
}


Related Topics



Leave a reply



Submit