How can I create an array that contains unique strings? - arrays

I want to create an array that contains unique strings. How can I do that?
var paths = make([]string, 0)
func main() {
// Members are added dynamically
paths = append(paths, "aaa")
paths = append(paths, "bbb")
paths = append(paths, "bbb")
paths = append(paths, "ccc")
// convert ["aaa", "bbb", "bbb", "ccc"] -> ["aaa", "bbb", "ccc"]
// or can I use some class that disallow the same string automaticaly?
}

If you want a collection of unique elements, that is the Set data type. Go does not have a builtin set data type, but you can use a map to act as a set: keys in a map must be unique.
For a "nice" set, use a map with bool value type (with true values) and exploit the zero value. For a set with the smallest memory footprint, use a map with struct{} value type as values of struct{} type occupy no memory; and use the comma-ok idiom to tell if a value is in the set / map.
Here's how the "nice" version of set looks like. Instead of a slice add your elements to a map[string]bool as the key with a true as the value:
m := make(map[string]bool)
m["aaa"] = true
m["bbb"] = true
m["bbb"] = true
m["ccc"] = true
To check if an element is already in the collection (map), you can simply use an index expression:
exists := m["somevalue"]
This exploits the zero value, that is if the map does not yet contain an element, the zero value of the value type is returned which is false in case of bool type, properly indicating that the element is not in the collection.
Elements in a map have no fixed order. If you need to keep the order (e.g. insertion order), then use a slice (to remember the order) and a map (to tell if an element to be added is new). This is easiest with a helper add() function:
var m = make(map[string]bool)
var a = []string{}
func main() {
add("aaa")
add("bbb")
add("bbb")
add("ccc")
}
func add(s string) {
if m[s] {
return // Already in the map
}
a = append(a, s)
m[s] = true
}

Related

How do I convert a byte slice of unknown size to a byte array?

I need to unmarshal some data, and in one case, the marshaled data represents a map with a byte array as a key.
Slices are not allowed as map keys, however arrays are. But the problem here is that arrays can't be created with a non-constant size as far as I can tell.
Example:
package main
import (
"fmt"
"reflect"
)
func getHashable(value interface{}) interface{} {
rfl := reflect.ValueOf(value)
if rfl.Kind() == reflect.Slice && rfl.Type().Elem().Kind() == reflect.Uint8 {
slice, ok := value.([]uint8)
if !ok {
panic(fmt.Errorf("Could not coerce to []uint8"))
}
var arr [len(slice)]uint8 // This fails
copy(arr, slice)
value = arr
}
return value
}
func unmarshalMap(serialized []byte) map[interface{}]interface{} {
result := make(map[interface{}]interface{})
for len(serialized) > 0 {
var value interface{}
key, bytesConsumed := deserializeValue(serialized)
serialized = serialized[bytesConsumed:]
value, bytesConsumed = deserializeValue(serialized)
serialized = serialized[bytesConsumed:]
result[getHashable(key)] = value
}
}
If deserializeValue() returns a []byte, then it can't be stored as a key in the result map. An array would work, but I can't create an array because I don't know what size I'll need until runtime, and it only allows compile time constants.
A simplified version https://play.golang.org/p/wkYGs3S-uSD fails with the error
./prog.go:15:12: non-constant array bound len(slice)
How can I use an array of bytes that I've unmarshaled as a key in a map in Go?
While use a string is clearly the better way, if the code you don't control uses a byte array as key, here is how you can turn the byte slice into an array as an interface using reflect.
varr := reflect.New(reflect.ArrayOf(len(slice), reflect.TypeOf(uint8(0))))
reflect.Copy(varr.Elem(), reflect.ValueOf(slice))
return varr.Elem().Interface()
Please consider other options before using this.
Playground: https://play.golang.org/p/CXsxZwgjiRR
Use string instead of a fixed size array of bytes. A string can hold an arbitrary sequence of bytes.
func getHashable(value interface{}) interface{} {
rfl := reflect.ValueOf(value)
if rfl.Kind() == reflect.Slice && rfl.Type().Elem().Kind() == reflect.Uint8 {
value = string(rfl.Bytes())
}
return value
}
If you are only need to handle []byte and not named types for []byte, use type assertions instead of reflection:
func getHashable(value interface{}) interface{} {
switch value := value.(type) {
case []byte:
return string(value)
default:
return value
}
}
If the user of the map needs to distinguish string keys from keys created form []byte, define a string type to distinguish those values:
type convertedSlice string
Replace use of string() conversion in the code above with convertedSlice().
The application can check for converted keys with:
_, ok := key.(convertedSlice) // ok is true if key is converted slice.
and convert the keys back to []byte with:
cv, ok := key.(convertedSice)
if ok {
key = []byte(cv)
}

How do I make two arrays in which first one would be values and second one would be keys for those values?

I am creating two arrays.
First one contains images, second one contains equal amount of numbers.
How do I make second array of integers correspond to first array, so I would have a specific integer value for each picture?
Like i said in my comment. You could apply a convention, then use an extension on Int to return the image the number describes:
let arrInt = [0, 1, 2, 3] //any number of integers
let cardnames = ["AceOfSpades", "OneOfSpades", "TwoOfSpades"] //etc...
extension Int {
var cardName : UIImage? {
guard self <= 51 else { return nil } //because any number greater than this would not represent a card in your 53-card deck
return UIImage(named: cardNames[self])
}
}
You would essentially use it as:
func AllImagesInTheDeck() -> [UIImage] {
var images : [UIImage] = []
for integer in arrInt {
if let image = integer.cardName {
images.append(image)
}
}
return images
}
From then on, you can manipulate the arrInt itself, of individual integer arrays for each player, and to return their card images, you could either call the AllImages method (which shouldn't be a hard hit on performance since array length shouldn't be too long for this case. Or, you can directly manipulate the integer arrays from there on out, and add more methods to determine which new card images are added, etc. This is while if any struct or class must be avoided, otherwise if you can, incorporating this approach with CRD's class example would work well too.
After the comments you could start with:
class PairedArrays
{
// instance variables - arrays for the images and values, start of empty
var images : [NSImage] = []
var values : [Int] = []
// add a new image/value pair
func addPair(image : NSImage, values : Int) -> Void { ... }
// retrieve integer associated with image
func getAssociatedInt(key : NSImage) -> Int { ... }
}
Now you need to:
Read up on classes in Swift
Fill in the ...
Make it generic so it works with types other than images and integers (optional, but useful knowledge)
Having used it as a learning tool try using an array of struct which will guarantee images & values are always added in pairs (think struct PlayingCard { ... })
Now try it with a dictionary
Compare the last two and decide which suits your application model the best
HTH

Implement Scan interface to read json array into map

I am fetching a JSON array from PostgreSQL, and I would like to read it into a map. I am able to Unmarshal the values into a []string slice, but what I actually want is a map[string]bool.
I've written a custom type for the column with a Scan interface that converts the JSON array into a slice of strings first, then reads each string into the custom map type as keys.
type custMap map[string]bool
func (m *custMap) Scan(src interface{}) error {
b, ok := src.([]byte)
if !ok {
return error(errors.New("Error Scanning Array"))
}
s := make([]string, 0)
json.Unmarshal(b, &s)
for _, v := range s {
(*m)[v] = true
}
return nil
}
type data struct {
vals custMap `json: "vals"`
}
The query I am trying to scan returns a row with a column vals which is a JSON array: ["some", "arr", "vals"], where the custom type is used like so:
var d models.data
sqlDB.QueryRow().Scan(&d.vals)
My expected output is a struct with the following shape
{ vals: map[string]bool { "some": true, "arr": true, "vals": true }
This compiles fine, but my code panics with "assignment to entry in nil map"
How can I fix my Scan function? Is it even possible to do this with a map type?
You are calling your method Scan of type *custMap on a unitialised map. Initialize d.vals either like
d.vals = custMap{}
or
d.vals = make(custMap)
Other answers already provide an explanation.
The Go Programming Language Specification
Map types
A map is an unordered group of elements of one type, called the
element type, indexed by a set of unique keys of another type, called
the key type. The value of an uninitialized map is nil.
A new, empty map value is made using the built-in function make, which
takes the map type and an optional capacity hint as arguments:
make(map[string]int)
make(map[string]int, 100)
The initial capacity does not bound its size: maps grow to accommodate
the number of items stored in them, with the exception of nil maps. A
nil map is equivalent to an empty map except that no elements may be
added.
I don't see a make to initialize your map: "A nil map is equivalent to an empty map except that no elements may be added."

Array in Dictionary in Swift

My question is really simple and I guess it’s easy to do but, how to add an object into an array when the array is held in a dictionary in Swift language?
var dictionary = [String: [String]]()
for course in self.category.m_course_array
{
let firstChar = String(Array(course.getTitle())[0]).uppercaseString
dictionary[firstChar] = // How to add an element into the array of String
}
Not so easy as you might think, in fact. It's is a bit messy since you need to handle the fact that when the key isn’t present, you need to initialize the array. Here’s one way of doing it (code altered to be similar but stand-alone):
var dictionary = [String: [String]]()
let courses = ["Thing","Other Thing","Third Thing"]
for course in courses {
// note, using `first` with `if…let` avoids a crash in case
// you ever have an empty course title
if let firstChar = first(course).map({String($0).uppercaseString}) {
// get out the current values
let current = dictionary[firstChar]
// if there were none, replace nil with an empty array,
// then append the new entry and reassign
dictionary[firstChar] = (current ?? []) + [course]
}
}
Alternatively, if you want to use .append you could do this:
// even though .append returns no value i.e. Void, this will
// return Optional(Void), so can be checked for nil in case
// where there was no key present so no append took place
if dictionary[firstChar]?.append(course) == nil {
// in which case you can insert a single entry
dictionary[firstChar] = [course]
}
Try this
dictionary[firstChar].append(yourElement)
Since dictionary[firstChar] should get you your array

How can I define a map whose values contain a fixed length array of type String?

I'm attempting to represent the basic strategy of a blackjack game as a map with integer keys whose values are a fixed length array of strings.
The keys represent the value of the player's hand, the array index represents the value of the dealers up card (hence the fixed length array of size 10 corresponding to card values 2-11). The string value in the array at the position corresponding to the dealer's up card contains the ideal play (stay, hit, split, double).
IE) player hand value is a hard 8, dealer up card is a 2. Basic strategy says the player should hit. To determine this using my map, I would get the array whose key is 8(player hand value = 8) and then looking at the string in array index 0 (Dealer up card = 2).
I've attempted to define it this way:
val hardHandBasicStrategy = collection.mutable.Map[Int,Array[String](10)]
but Scala doesn't seem to like this...
Please help me understand what I've done wrong, and/or suggest a way to make it work.
Scala doesn't have a type that represents arrays of a fixed size. You can either simply use arrays of size ten--this is what is normally done--or, if you want stronger guarantees that it really is size ten, you can construct a ten-long-array-class yourself:
class ArrayTen[T: ClassManifest](zero: T) {
protected val data = Array.fill(10)(zero)
def apply(i: Int) = data(i)
def update(i: Int, t: T) { data(i) = t }
protected def set(ts: Array[T]) { for (i <- data.indices) data(i) = ts(i) }
def map[U: ClassManifest](f: T => U) = {
val at = new ArrayTen(null.asInstanceOf[U])
at.set(data.map(f))
at
}
def foreach(f: T => Unit) { data.map(f) }
override def toString = data.mkString("#10[",",","]")
override def hashCode = scala.util.MurmurHash.arrayHash(data)
override def equals(a: Any) = a match {
case a: ArrayTen[_] => (data,a.data).zipped.forall(_ == _)
case _ => false
}
// Add other methods here if you really need them
}
Example:
scala> new ArrayTen("(nothing)")
res1: ArrayTen[java.lang.String] =
#10[(nothing),(nothing),(nothing),(nothing),(nothing),
(nothing),(nothing),(nothing),(nothing),(nothing)]
scala> res1(3) = "something!!!"
scala> res1
res3: ArrayTen[java.lang.String] =
#10[(nothing),(nothing),(nothing),something!!!,(nothing),
(nothing),(nothing),(nothing),(nothing),(nothing)]
If you need the the fixed-length array to take a parameter that determines the length, then you should
trait Size { size: Int }
class ArraySize[S <: Size, T: ClassManifest](zero: T, s: Size) {
protected val data = Array.fill(s.size)(zero)
...
}
You won't have all the collections goodies unless you reimplement them, but then again you don't want most of the goodies, since most of them can change the length of the array.

Resources