0

I'm porting some old PHP script to Go in order to achieve better performance. However, the old PHP is full of multidimensional arrays. Some excerpt from the codebase:

while (($row = $stmt->fetch(PDO::FETCH_ASSOC)) !== false) {
    $someData[$row['column_a']][$row['column_b']] = $row;
}

// ... more queries and stuff

if (isset($moreData['id']) && isset($anotherData['id']) && $someData[$anotherData['id']][$moreData['id']]) {
    echo $someData[$anotherData['id']][$moreData['id']];
}

Awful, i know, but i can't change the logic. I made the whole script perform much better by compiling with phc, but moving to a procedural, statically-typed language seems like a better move. How can i replicate those data structures efficiently with Go or Rust? It needs to be fault-tolerant when it comes to checking indexes, there's a lot of issets all around the script to check if the identifiers exist in the data structures.

vinnylinux
  • 7,050
  • 13
  • 61
  • 127
  • Multidimensional associative arrays are easy (in Rust; probably in Go too), the real question is whether the key and value types are consistent and hence can be described in a static type system. –  Oct 04 '14 at 19:12

2 Answers2

4

In Go, this would be represented as a map. The syntax is map[key]value. So for example to store a multidimensional map of [string, string] -> int it would be map[string]map[string]int. If you know your indices are integers and densely packed, then you'd want to use slices. Those are simpler and look like [][]type.

As for the checking for a key existing, use this syntax, where m is a map:

if val, ok := m[key1][key2]; ok {
    ///Do something with val
}

Remember that to add a key to a multidimensional map you'd have to make sure the inner map is allocated before adding to it.

if _, ok := m[key]; !ok {
    m[key] = make(map[string]int)
}
m[key1][key2] = value

Obviously you'd want to wrap this up in a type with methods or a few simple functions.

Logiraptor
  • 1,496
  • 10
  • 14
3

Rust

PHP arrays are actually associative arrays, also known as maps or dictionaries. Rust uses the name Map in its standard library. The Map trait provides an interface for a variety of implementations. In particular, this trait defines a contains_key method, which you can use to check if the map contains a particular key (instead of writing isset($array[$key]), you write map.contains_key(key)).

Map has two type parameters: K is the type of the map's keys (i.e. the values you use as an index) and V is the type of the map's values.

If you need your map to contain keys and/or values of various types, you'll need to use the Any trait. For example, if the keys are strings and the values are of various types, you could use HashMap<String, Box<Any>> (Box is necessary because trait objects are unsized; see this answer for more information). Check out the documentation for AnyRefExt and AnyMutRefExt to see how to work with an Any value.

However, if the possible types are relatively limited, it might be easier for you to define your own trait and use that trait instead of Any so that you can implement operations on those types without having to cast explicitly everywhere you need to use the values (plus, you can add types by adding an impl without having to change all the places that use values).

Community
  • 1
  • 1
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155
  • Do you suggest any MySQL lib for Rust? – vinnylinux Oct 04 '14 at 20:18
  • Thia answer is nicely put, but suggest Rust, completely ignoring GO. Rust is looking very, very promisig, but it didnt hit 1.0 yet, and using it in production is very risky, as API may break at any time. If its development not intended to use in production - go ahead, its great to know fresh and good languages before most of people do :). – Jarema Oct 05 '14 at 03:01
  • @Jarema This advice is now out of date. Rust is nice and stable. – wizzwizz4 Dec 15 '19 at 17:55