{"id":64,"date":"2009-01-24T21:32:59","date_gmt":"2009-01-24T20:32:59","guid":{"rendered":"http:\/\/muratyaman.co.uk\/wp\/?p=64"},"modified":"2020-04-01T12:56:55","modified_gmt":"2020-04-01T11:56:55","slug":"php-associative-arrays-for-c-net","status":"publish","type":"post","link":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/2009\/01\/php-associative-arrays-for-c-net\/","title":{"rendered":"PHP Associative Arrays for C# .NET"},"content":{"rendered":"<p>I always loved the ease of use of arrays in PHP. Simple, dynamic arrays; arrays with integer indexes or string keys; hash tables, maps, collections, resizable variant arrays; you name it.<\/p>\n<p>In C++, you can refer to <a href=\"http:\/\/en.wikipedia.org\/wiki\/Standard_Template_Library\">Standard Template Library (STL)<\/a> and use <b>vectors<\/b> for example if you need a regular dynamically sized array, integers used as keys; or <b>maps<\/b> if you need to use strings as keys.<\/p>\n<p>In C#, namespace <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ybcx56wz(VS.80).aspx\">Collections <\/a> contains similar classes to achieve same results; where a C++ <b>vector<\/b> is a <b>List<\/b> or <b>ArrayList<\/b>, and a <b>map<\/b> is a <b>Hashtable<\/b> or <b>Dictionary<\/b>.<\/p>\n<p>PHP has also similar library called <a href=\"http:\/\/uk.php.net\/spl\">Standard PHP Library (SPL)<\/a>.<\/p>\n<p><a href=\"http:\/\/java.sun.com\/docs\/books\/tutorial\/collections\/index.html\">Java Collections Framework<\/a> does the same job with lists and maps.<\/p>\n<p>For common problems, common solutions are provided in these libraries.<\/p>\n<pre lang=\"csharp\">\r\nusing System;\r\nusing System.Collections;\r\nusing System.Collections.Generic;\r\n\r\nnamespace MyNamespace\r\n{\r\n    class CAssocArray<T> : System.Collections.IEnumerable\r\n    {\r\n        public const bool USE_INT_AUTOINDEX = true;\r\n        public const int INDEX_TYPE_INT = 0;\r\n        public const int INDEX_TYPE_STRING = 1;\r\n\r\n        public enum INDEX_TYPE {INTEGER, STRING};\r\n\r\n        private const int nil = -9999999;\r\n        private int my_max_key;\/\/my_min_key, my_first_key, my_last_key;\r\n        \r\n        private Dictionary<int, T> d;\r\n\r\n        \/\/if true, it is like 0-based normal array, sequential numbers will be used as keys\r\n        private bool isIntAutoIndexed;\r\n        private INDEX_TYPE index_type;\r\n\r\n        public CAssocArray()\r\n        {\r\n            this.init(0, true);\r\n        }\r\n\r\n        public CAssocArray(CAssocArray<T> a)\r\n        {\r\n            this.init(a.index_type, a.isIntAutoIndexed);\r\n            foreach (int k in a.d.Keys)\r\n            {\r\n                \/\/Object o = a.d[k]; T t = (T) o; this.d[k] = t.MemberwiseClone();\r\n                this.d[k] = a.d[k];\r\n            }\r\n        }\r\n\r\n        public CAssocArray(INDEX_TYPE index_type, bool isIntAutoIndexed)\r\n        {\r\n            this.init(index_type, isIntAutoIndexed);\r\n        }\r\n\r\n        private void init(INDEX_TYPE index_type, bool isIntAutoIndexed)\r\n        {\r\n            my_max_key = nil;\/\/my_first_key = nil; my_last_key = nil;\r\n            d = new Dictionary<int, T>();\r\n            this.index_type = index_type;\r\n            this.isIntAutoIndexed = isIntAutoIndexed;\r\n        }\r\n        public bool isIndexType_Int()\r\n        {\r\n            return this.index_type == CAssocArray<T>.INDEX_TYPE.INTEGER;\/\/INDEX_TYPE_INT;\r\n        }\r\n        public bool isIndexType_String()\r\n        {\r\n            return this.index_type == CAssocArray<T>.INDEX_TYPE.STRING;\/\/INDEX_TYPE_STRING;\r\n        }\r\n        public int size()\/\/alias for c++ \"vector\" class\r\n        {\r\n            return d.Count;\r\n        }\r\n\r\n        public int Length()\r\n        {\r\n            return d.Count;\r\n        }\r\n\r\n        public int Count()\r\n        {\r\n            return d.Count;\r\n        }\r\n\r\n        public void push_back(T value)\/\/alias for c++ \"vector\" class\r\n        {\r\n            this.insert(value);\r\n        }\r\n\r\n        \/**\r\n         * Insert value, use the next number in the sequence as key\r\n         *\/\r\n        public void insert(T value)\r\n        {\r\n            if (my_max_key == nil) my_max_key = -1;\r\n            int key = (my_max_key + 1);\r\n            \/\/string skey = key.ToString();\r\n            this.insert(key, value);\r\n        }\r\n\r\n        public void insert(string strKey, T value)\r\n        {\r\n            int key = strKey.GetHashCode();\r\n            this.insert(key, value);\r\n        }\r\n\r\n        public void insert(int key, T value)\r\n        {\r\n            d.Add(key, value);\r\n            if (key > my_max_key) my_max_key = key;\r\n        }\r\n\r\n\r\n        public bool remove(int key)\r\n        {\r\n            bool r = false;\r\n            if (key != nil)\r\n            {\r\n                if (d.ContainsKey(key))\r\n                {\r\n                    r = d.Remove(key);\r\n                    if (key == my_max_key) my_max_key = this.getMaxKey();\r\n                }\r\n            }\r\n            return r;\r\n        }\r\n\r\n        public bool clear()\r\n        {\r\n            d.Clear();\r\n            my_max_key = nil;\r\n            return true;\r\n        }\r\n\r\n        public bool removeFirst()\r\n        {\r\n            int key = this.getFirstKey();\r\n            return this.remove(key);\r\n        }\r\n\r\n        public bool removeLast()\r\n        {\r\n            int key = this.getLastKey();\r\n            return this.remove(key);\r\n        }\r\n\r\n        public bool pop_back()\r\n        {\r\n            return this.removeLast();\r\n        }\r\n\r\n        public List<int> getKeyList()\r\n        {\r\n            return d.Keys.ToList();\r\n        }\r\n        public List<int> keys()\r\n        {\r\n            return d.Keys.ToList();\r\n        }\r\n\r\n        public List<T> getValueList()\r\n        {\r\n            return d.Values.ToList();\r\n        }\r\n\r\n        public List<T> list()\r\n        {\r\n            return d.Values.ToList();\r\n        }\r\n\r\n        public List<T> values()\r\n        {\r\n            return d.Values.ToList();\r\n        }\r\n\t\t\t\t\r\n        public IEnumerator GetEnumerator()\r\n        {\r\n            List<T> list = this.d.Values.ToList();\r\n            foreach (T item in list)\r\n            {\r\n                yield return item;\r\n            }\r\n        }\r\n\t\t\t\t\r\n        private int getLastKey()\r\n        {\r\n            List<int> l = this.getKeyList();\r\n            if (l.Count == 0) return nil;\r\n            return l.Last();\r\n        }\r\n\r\n        private int getFirstKey()\r\n        {\r\n            List<int> l = this.getKeyList();\r\n            if (l.Count == 0) return nil;\r\n            return l.First();\r\n        }\r\n\t\t\t\t\r\n        private int getMaxKey()\r\n        {\r\n            List<int> l = this.getKeyList();\r\n            if (l.Count == 0) return nil;\r\n            return l.Max();\r\n        }\r\n\r\n        public T first()\r\n        {\r\n            int key = this.getFirstKey();\r\n            return this.get(key);\r\n        }\r\n\r\n        public T last()\r\n        {\r\n            int key = this.getLastKey();\r\n            return this.get(key);\r\n        }\r\n\r\n        public T this[int key]\r\n        {\r\n            get\r\n            {\r\n                return this.getI(key);\r\n            }\r\n            set\r\n            {\r\n                this.setI(key, value);\r\n            }\r\n        }\r\n\r\n        public T this[string key]\r\n        {\r\n            get\r\n            {\r\n                return this.getS(key);\r\n            }\r\n            set\r\n            {\r\n                this.setS(key, value);\r\n            }\r\n        }\r\n\r\n\r\n        private T get(int key)\/\/HashCode\r\n        {\r\n            T t = default(T);\r\n            if (d.ContainsKey(key)) t = d[key];\r\n            return t;\r\n        }\r\n\r\n        private T getI(int key)\r\n        {\r\n            int Hkey = this.isIntAutoIndexed ? key : key.ToString().GetHashCode();\r\n            return this.get(Hkey);\r\n        }\r\n\r\n        private T getS(string key)\r\n        {\r\n            int Hkey = key.ToString().GetHashCode();\r\n            return this.get(Hkey);\r\n        }\r\n\r\n        private void set(int key, T value)\/\/HashCode, value\r\n        {\r\n            if (d.ContainsKey(key))\r\n                d[key] = value;\r\n            else\r\n                this.insert(key, value);\r\n        }\r\n\r\n        private void setI(int key, T value)\r\n        {\r\n            int Hkey = this.isIndexType_Int() ? key : key.ToString().GetHashCode();\r\n            this.set(Hkey, value);\r\n        }\r\n\r\n        private void setS(string key, T value)\r\n        {\r\n            int Hkey = key.GetHashCode();\r\n            this.set(Hkey, value);\r\n        }\r\n\r\n    }\/\/end class\r\n\r\n}\/\/end namespace\r\n\r\n\/\/Now, how we can use this class:\r\n\r\nnamespace MyNamespace\r\n{\r\n\tclass Edge\r\n\t{\r\n\t\tpublic int target;\r\n\t\tpublic int input;\r\n\t\tpublic double probability;\r\n\t\t\r\n\t\tpublic Edge(int target, int input, double probability)\r\n\t\t{\r\n\t\t\tthis.target = target;\r\n\t\t\tthis.input = input;\r\n\t\t\tthis.probability = probability;\r\n\t\t}\r\n\t}\r\n\r\n\tclass Edges : CAssocArray<Edge>\r\n\t{\r\n\r\n\t\tpublic Edge getClassWithMaxProbability()\r\n\t\t{\r\n\t\t\tdouble max_prob = 0.0; int max_idx = 0;\r\n\t\t\tint n = this.size();\r\n\t\t\tEdge e = new Edge();\r\n\t\t\tif (n == 0)\r\n\t\t\t{\r\n\t\t\t\treturn e;\r\n\t\t\t}\r\n\t\t\tforeach (int i in this.getKeyList())\r\n\t\t\t{\r\n\t\t\t\tEdge ei = this[i];\r\n\t\t\t\tif (max_prob < ei.probability)\r\n\t\t\t\t{\r\n\t\t\t\t\tmax_prob = ei.probability;\r\n\t\t\t\t\tmax_idx = ei.target;\r\n\t\t\t\t\te = ei;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn e;\r\n\t\t}\r\n\t}\r\n\r\n\tclass Node\r\n\t{\r\n\t\tpublic double probability;\r\n\t\tpublic Edges edges;\r\n\r\n\t\tpublic Node(double probability)\r\n\t\t{\r\n\t\t\tthis.probability = probability;\r\n\t\t\tthis.edges = new Edges();\r\n\t\t}\r\n\t}\r\n\r\n\tclass Nodes : CAssocArray<Node>\r\n\t{\r\n\t\tpublic Nodes()\r\n\t\t{\r\n\t\t\t\/\/do something\r\n\t\t}\r\n\t}\r\n\r\n\tclass Program{\r\n\r\n\t\tstatic void Main(string[] args)\r\n\t\t{\r\n\t\t\tNodes nodes = new Nodes();\r\n\t\t\tNode node0 = new Node(1.0);\r\n\t\t\tNode node1 = new Node(0.0);\r\n\t\t\tNode node2 = new Node(0.0);\r\n\t\t\tNode node3 = new Node(0.0);\r\n\t\t\tnodes.insert(node0);\r\n\t\t\tnodes[1] = node1;\r\n\t\t\tnodes.insert(node2);\r\n\t\t\tnodes[3] = node3;\r\n\t\t\t\r\n\t\t\tnode0.edges.insert(new Edge(1, 11, 0.5));\r\n\t\t\tnode0.edges.insert(new Edge(2, 12, 0.5));\r\n\t\t\t\r\n\r\n\t\t\tnode1.edges[2] = new Edge(2, 12, 0.25);\r\n\t\t\tnode1.edges[3] = new Edge(3, 13, 0.75);\r\n\t\t\t\r\n\t\t\tnode2.edges[1] = new Edge(1, 11, 0.75);\r\n\t\t\tnode2.edges[3] = new Edge(3, 13, 0.25);\r\n\t\t\t\r\n\t\t\tnode3.edges[0] = new Edge(0, 10, 1.0);\r\n\t\t\t\r\n\t\t\tnodes[0].probability -= 0.25;\r\n\t\t\tnodes[1].probability += 0.25;\r\n\t\t\t\r\n\t\t\tnodes[0].edges[0].probability -= 0.1;\r\n\t\t\tnodes[0].edges[1].probability += 0.1;\r\n\t\t\t\r\n\t\t\tnodes[3].edges[0].probability = 0.5;\r\n\t\t\tnodes[3].edges[1] = new Edge(1, 11, 0.5);\r\n\r\n\t\t\tforeach(int i in nodes.getKeyList())\r\n\t\t\t{\r\n\t\t\t\tNode node = nodes[i];\r\n\t\t\t\tforeach(int j in node.edges.getKeyList())\r\n\t\t\t\t{\r\n\t\t\t\t\tEdge edge = node.edges[j];\r\n\t\t\t\t\t\/\/do something\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t}\r\n\r\n\t}\r\n\r\n}\/\/end namespace\r\n\r\n<\/pre>\n<p>What would it look like? This is a simple state machine with some nodes and edges linking nodes to each other.<\/p>\n<p><img decoding=\"async\" src=\"\/images\/fsm-sample.jpg\" alt=\"State Machine\" \/><\/p>\n","protected":false},"excerpt":{"rendered":"<p>I always loved the ease of use of arrays in PHP. Simple, dynamic arrays; arrays with integer indexes or string keys; hash tables, maps, collections, resizable variant arrays; you name it.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[44,74,47,65,26,75],"class_list":["post-64","post","type-post","status-publish","format-standard","hentry","category-technology","tag-c-sharp","tag-c","tag-java","tag-oop","tag-php","tag-stl"],"_links":{"self":[{"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/posts\/64","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/comments?post=64"}],"version-history":[{"count":3,"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/posts\/64\/revisions"}],"predecessor-version":[{"id":982,"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/posts\/64\/revisions\/982"}],"wp:attachment":[{"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/media?parent=64"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/categories?post=64"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.muratyaman.co.uk\/blog\/index.php\/wp-json\/wp\/v2\/tags?post=64"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}