Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
We don’t allow questions seeking recommendations for books, tools, software libraries, and more. You can edit the question so it can be answered with facts and citations.
Closed 2 years ago.
Improve this question
Does anyone know where I can find an example of how to construct a trie in C#? I'm trying to take a dictionary/list of words and create a trie with it.
This is my own code, pulled from my answer to How to find a word from arrays of characters? :
public class Trie
{
public struct Letter
{
public const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static implicit operator Letter(char c)
{
return new Letter() { Index = Chars.IndexOf(c) };
}
public int Index;
public char ToChar()
{
return Chars[Index];
}
public override string ToString()
{
return Chars[Index].ToString();
}
}
public class Node
{
public string Word;
public bool IsTerminal { get { return Word != null; } }
public Dictionary<Letter, Node> Edges = new Dictionary<Letter, Node>();
}
public Node Root = new Node();
public Trie(string[] words)
{
for (int w = 0; w < words.Length; w++)
{
var word = words[w];
var node = Root;
for (int len = 1; len <= word.Length; len++)
{
var letter = word[len - 1];
Node next;
if (!node.Edges.TryGetValue(letter, out next))
{
next = new Node();
if (len == word.Length)
{
next.Word = word;
}
node.Edges.Add(letter, next);
}
node = next;
}
}
}
Take a look at this codeplex project:
https://github.com/gmamaladze/trienet
It is a library containing several different variants of well tested generic c# trie classes including patricia trie and parallel trie.
Trie – the simple trie, allows only prefix search, like .Where(s => s.StartsWith(searchString))
SuffixTrie - allows also infix search, like .Where(s => s.Contains(searchString))
PatriciaTrie – compressed trie, more compact, a bit more efficient during look-up, but a quite slower durig build-up.
SuffixPatriciaTrie – the same as PatriciaTrie, also enabling infix search.
ParallelTrie – very primitively implemented parallel data structure which allows adding data and retriving results from different threads simultaneusly.
A simple Trie implementation.
http://github.com/bharathkumarms/AlgorithmsMadeEasy/blob/master/AlgorithmsMadeEasy/Tries.cs
using System;
using System.Collections.Generic;
using System.Linq;
namespace AlgorithmsMadeEasy
{
class Tries
{
TrieNode root;
public void CreateRoot()
{
root = new TrieNode();
}
public void Add(char[] chars)
{
TrieNode tempRoot = root;
int total = chars.Count() - 1;
for (int i = 0; i < chars.Count(); i++)
{
TrieNode newTrie;
if (tempRoot.children.Keys.Contains(chars[i]))
{
tempRoot = tempRoot.children[chars[i]];
}
else
{
newTrie = new TrieNode();
if (total == i)
{
newTrie.endOfWord = true;
}
tempRoot.children.Add(chars[i], newTrie);
tempRoot = newTrie;
}
}
}
public bool FindPrefix(char[] chars)
{
TrieNode tempRoot = root;
for (int i = 0; i < chars.Count(); i++)
{
if (tempRoot.children.Keys.Contains(chars[i]))
{
tempRoot = tempRoot.children[chars[i]];
}
else
{
return false;
}
}
return true;
}
public bool FindWord(char[] chars)
{
TrieNode tempRoot = root;
int total = chars.Count() - 1;
for (int i = 0; i < chars.Count(); i++)
{
if (tempRoot.children.Keys.Contains(chars[i]))
{
tempRoot = tempRoot.children[chars[i]];
if (total == i)
{
if (tempRoot.endOfWord == true)
{
return true;
}
}
}
else
{
return false;
}
}
return false;
}
}
public class TrieNode
{
public Dictionary<char, TrieNode> children = new Dictionary<char, TrieNode>();
public bool endOfWord;
}
}
/*
Calling Code:
Tries t = new Tries();
t.CreateRoot();
t.Add("abc".ToCharArray());
t.Add("abgl".ToCharArray());
t.Add("cdf".ToCharArray());
t.Add("abcd".ToCharArray());
t.Add("lmn".ToCharArray());
bool findPrefix1 = t.FindPrefix("ab".ToCharArray());
bool findPrefix2 = t.FindPrefix("lo".ToCharArray());
bool findWord1 = t.FindWord("lmn".ToCharArray());
bool findWord2 = t.FindWord("ab".ToCharArray());
bool findWord3 = t.FindWord("cdf".ToCharArray());
bool findWord4 = t.FindWord("ghi".ToCharArray());
*/
Quick google results:
Taken from: Trie Generic
By Glenn Slayden
attributed to Kerry D. Wong
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
public class Trie<TValue> : System.Collections.IEnumerable, IEnumerable<Trie<TValue>.TrieNodeBase>
{
public abstract class TrieNodeBase
{
protected TValue m_value = default(TValue);
public TValue Value
{
get { return m_value; }
set { m_value = value; }
}
public bool HasValue { get { return !Object.Equals(m_value, default(TValue)); } }
public abstract bool IsLeaf { get; }
public abstract TrieNodeBase this[char c] { get; }
public abstract TrieNodeBase[] Nodes { get; }
public abstract void SetLeaf();
public abstract int ChildCount { get; }
public abstract bool ShouldOptimize { get; }
public abstract KeyValuePair<Char, TrieNodeBase>[] CharNodePairs();
public abstract TrieNodeBase AddChild(char c, ref int node_count);
/// <summary>
/// Includes current node value
/// </summary>
/// <returns></returns>
public IEnumerable<TValue> SubsumedValues()
{
if (Value != null)
yield return Value;
if (Nodes != null)
foreach (TrieNodeBase child in Nodes)
if (child != null)
foreach (TValue t in child.SubsumedValues())
yield return t;
}
/// <summary>
/// Includes current node
/// </summary>
/// <returns></returns>
public IEnumerable<TrieNodeBase> SubsumedNodes()
{
yield return this;
if (Nodes != null)
foreach (TrieNodeBase child in Nodes)
if (child != null)
foreach (TrieNodeBase n in child.SubsumedNodes())
yield return n;
}
/// <summary>
/// Doesn't include current node
/// </summary>
/// <returns></returns>
public IEnumerable<TrieNodeBase> SubsumedNodesExceptThis()
{
if (Nodes != null)
foreach (TrieNodeBase child in Nodes)
if (child != null)
foreach (TrieNodeBase n in child.SubsumedNodes())
yield return n;
}
/// <summary>
/// Note: doesn't de-optimize optimized nodes if re-run later
/// </summary>
public void OptimizeChildNodes()
{
if (Nodes != null)
foreach (var q in CharNodePairs())
{
TrieNodeBase n_old = q.Value;
if (n_old.ShouldOptimize)
{
TrieNodeBase n_new = new SparseTrieNode(n_old.CharNodePairs());
n_new.m_value = n_old.m_value;
Trie<TValue>.c_sparse_nodes++;
ReplaceChild(q.Key, n_new);
}
n_old.OptimizeChildNodes();
}
}
public abstract void ReplaceChild(Char c, TrieNodeBase n);
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Sparse Trie Node
///
/// currently, this one's "nodes" value is never null, because we leave leaf nodes as the non-sparse type,
/// (with nodes==null) and they currently never get converted back. Consequently, IsLeaf should always be 'false'.
/// However, we're gonna do the check anyway.
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class SparseTrieNode : TrieNodeBase
{
Dictionary<Char, TrieNodeBase> d;
public SparseTrieNode(IEnumerable<KeyValuePair<Char, TrieNodeBase>> ie)
{
d = new Dictionary<char, TrieNodeBase>();
foreach (var kvp in ie)
d.Add(kvp.Key, kvp.Value);
}
public override TrieNodeBase this[Char c]
{
get
{
TrieNodeBase node;
return d.TryGetValue(c, out node) ? node : null;
}
}
public override TrieNodeBase[] Nodes { get { return d.Values.ToArray(); } }
/// <summary>
/// do not use in current form. This means, run OptimizeSparseNodes *after* any pruning
/// </summary>
public override void SetLeaf() { d = null; }
public override int ChildCount { get { return d.Count; } }
public override KeyValuePair<Char, TrieNodeBase>[] CharNodePairs()
{
return d.ToArray();
}
public override TrieNodeBase AddChild(char c, ref int node_count)
{
TrieNodeBase node;
if (!d.TryGetValue(c, out node))
{
node = new TrieNode();
node_count++;
d.Add(c, node);
}
return node;
}
public override void ReplaceChild(Char c, TrieNodeBase n)
{
d[c] = n;
}
public override bool ShouldOptimize { get { return false; } }
public override bool IsLeaf { get { return d == null; } }
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Non-sparse Trie Node
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public class TrieNode : TrieNodeBase
{
private TrieNodeBase[] nodes = null;
private Char m_base;
public override int ChildCount { get { return (nodes != null) ? nodes.Count(e => e != null) : 0; } }
public int AllocatedChildCount { get { return (nodes != null) ? nodes.Length : 0; } }
public override TrieNodeBase[] Nodes { get { return nodes; } }
public override void SetLeaf() { nodes = null; }
public override KeyValuePair<Char, TrieNodeBase>[] CharNodePairs()
{
KeyValuePair<Char, TrieNodeBase>[] rg = new KeyValuePair<char, TrieNodeBase>[ChildCount];
Char ch = m_base;
int i = 0;
foreach (TrieNodeBase child in nodes)
{
if (child != null)
rg[i++] = new KeyValuePair<char, TrieNodeBase>(ch, child);
ch++;
}
return rg;
}
public override TrieNodeBase this[char c]
{
get
{
if (nodes != null && m_base <= c && c < m_base + nodes.Length)
return nodes[c - m_base];
return null;
}
}
public override TrieNodeBase AddChild(char c, ref int node_count)
{
if (nodes == null)
{
m_base = c;
nodes = new TrieNodeBase[1];
}
else if (c >= m_base + nodes.Length)
{
Array.Resize(ref nodes, c - m_base + 1);
}
else if (c < m_base)
{
Char c_new = (Char)(m_base - c);
TrieNodeBase[] tmp = new TrieNodeBase[nodes.Length + c_new];
nodes.CopyTo(tmp, c_new);
m_base = c;
nodes = tmp;
}
TrieNodeBase node = nodes[c - m_base];
if (node == null)
{
node = new TrieNode();
node_count++;
nodes[c - m_base] = node;
}
return node;
}
public override void ReplaceChild(Char c, TrieNodeBase n)
{
if (nodes == null || c >= m_base + nodes.Length || c < m_base)
throw new Exception();
nodes[c - m_base] = n;
}
public override bool ShouldOptimize
{
get
{
if (nodes == null)
return false;
return (ChildCount * 9 < nodes.Length); // empirically determined optimal value (space & time)
}
}
public override bool IsLeaf { get { return nodes == null; } }
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Trie proper begins here
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private TrieNodeBase _root = new TrieNode();
public int c_nodes = 0;
public static int c_sparse_nodes = 0;
// in combination with Add(...), enables C# 3.0 initialization syntax, even though it never seems to call it
public System.Collections.IEnumerator GetEnumerator()
{
return _root.SubsumedNodes().GetEnumerator();
}
IEnumerator<TrieNodeBase> IEnumerable<TrieNodeBase>.GetEnumerator()
{
return _root.SubsumedNodes().GetEnumerator();
}
public IEnumerable<TValue> Values { get { return _root.SubsumedValues(); } }
public void OptimizeSparseNodes()
{
if (_root.ShouldOptimize)
{
_root = new SparseTrieNode(_root.CharNodePairs());
c_sparse_nodes++;
}
_root.OptimizeChildNodes();
}
public TrieNodeBase Root { get { return _root; } }
public TrieNodeBase Add(String s, TValue v)
{
TrieNodeBase node = _root;
foreach (Char c in s)
node = node.AddChild(c,ref c_nodes);
node.Value = v;
return node;
}
public bool Contains(String s)
{
TrieNodeBase node = _root;
foreach (Char c in s)
{
node = node[c];
if (node == null)
return false;
}
return node.HasValue;
}
/// <summary>
/// Debug only; this is hideously inefficient
/// </summary>
public String GetKey(TrieNodeBase seek)
{
String sofar = String.Empty;
GetKeyHelper fn = null;
fn = (TrieNodeBase cur) =>
{
sofar += " "; // placeholder
foreach (var kvp in cur.CharNodePairs())
{
Util.SetStringChar(ref sofar, sofar.Length - 1, kvp.Key);
if (kvp.Value == seek)
return true;
if (kvp.Value.Nodes != null && fn(kvp.Value))
return true;
}
sofar = sofar.Substring(0, sofar.Length - 1);
return false;
};
if (fn(_root))
return sofar;
return null;
}
/// <summary>
/// Debug only; this is hideously inefficient
/// </summary>
delegate bool GetKeyHelper(TrieNodeBase cur);
public String GetKey(TValue seek)
{
String sofar = String.Empty;
GetKeyHelper fn = null;
fn = (TrieNodeBase cur) =>
{
sofar += " "; // placeholder
foreach (var kvp in cur.CharNodePairs())
{
Util.SetStringChar(ref sofar, sofar.Length - 1, kvp.Key);
if (kvp.Value.Value != null && kvp.Value.Value.Equals(seek))
return true;
if (kvp.Value.Nodes != null && fn(kvp.Value))
return true;
}
sofar = sofar.Substring(0, sofar.Length - 1);
return false;
};
if (fn(_root))
return sofar;
return null;
}
public TrieNodeBase FindNode(String s_in)
{
TrieNodeBase node = _root;
foreach (Char c in s_in)
if ((node = node[c]) == null)
return null;
return node;
}
/// <summary>
/// If continuation from the terminal node is possible with a different input string, then that node is not
/// returned as a 'last' node for the given input. In other words, 'last' nodes must be leaf nodes, where
/// continuation possibility is truly unknown. The presense of a nodes array that we couldn't match to
/// means the search fails; it is not the design of the 'OrLast' feature to provide 'closest' or 'best'
/// matching but rather to enable truncated tails still in the context of exact prefix matching.
/// </summary>
public TrieNodeBase FindNodeOrLast(String s_in, out bool f_exact)
{
TrieNodeBase node = _root;
foreach (Char c in s_in)
{
if (node.IsLeaf)
{
f_exact = false;
return node;
}
if ((node = node[c]) == null)
{
f_exact = false;
return null;
}
}
f_exact = true;
return node;
}
// even though I found some articles that attest that using a foreach enumerator with arrays (and Lists)
// returns a value type, thus avoiding spurious garbage, I had already changed the code to not use enumerator.
public unsafe TValue Find(String s_in)
{
TrieNodeBase node = _root;
fixed (Char* pin_s = s_in)
{
Char* p = pin_s;
Char* p_end = p + s_in.Length;
while (p < p_end)
{
if ((node = node[*p]) == null)
return default(TValue);
p++;
}
return node.Value;
}
}
public unsafe TValue Find(Char* p_tag, int cb_ctag)
{
TrieNodeBase node = _root;
Char* p_end = p_tag + cb_ctag;
while (p_tag < p_end)
{
if ((node = node[*p_tag]) == null)
return default(TValue);
p_tag++;
}
return node.Value;
}
public IEnumerable<TValue> FindAll(String s_in)
{
TrieNodeBase node = _root;
foreach (Char c in s_in)
{
if ((node = node[c]) == null)
break;
if (node.Value != null)
yield return node.Value;
}
}
public IEnumerable<TValue> SubsumedValues(String s)
{
TrieNodeBase node = FindNode(s);
if (node == null)
return Enumerable.Empty<TValue>();
return node.SubsumedValues();
}
public IEnumerable<TrieNodeBase> SubsumedNodes(String s)
{
TrieNodeBase node = FindNode(s);
if (node == null)
return Enumerable.Empty<TrieNodeBase>();
return node.SubsumedNodes();
}
public IEnumerable<TValue> AllSubstringValues(String s)
{
int i_cur = 0;
while (i_cur < s.Length)
{
TrieNodeBase node = _root;
int i = i_cur;
while (i < s.Length)
{
node = node[s[i]];
if (node == null)
break;
if (node.Value != null)
yield return node.Value;
i++;
}
i_cur++;
}
}
/// <summary>
/// note: only returns nodes with non-null values
/// </summary>
public void DepthFirstTraverse(Action<String,TrieNodeBase> callback)
{
Char[] rgch = new Char[100];
int depth = 0;
Action<TrieNodeBase> fn = null;
fn = (TrieNodeBase cur) =>
{
if (depth >= rgch.Length)
{
Char[] tmp = new Char[rgch.Length * 2];
Buffer.BlockCopy(rgch, 0, tmp, 0, rgch.Length * sizeof(Char));
rgch = tmp;
}
foreach (var kvp in cur.CharNodePairs())
{
rgch[depth] = kvp.Key;
TrieNodeBase n = kvp.Value;
if (n.Nodes != null)
{
depth++;
fn(n);
depth--;
}
else if (n.Value == null) // leaf nodes should always have a value
throw new Exception();
if (n.Value != null)
callback(new String(rgch, 0, depth+1), n);
}
};
fn(_root);
}
/// <summary>
/// note: only returns nodes with non-null values
/// </summary>
public void EnumerateLeafPaths(Action<String,IEnumerable<TrieNodeBase>> callback)
{
Stack<TrieNodeBase> stk = new Stack<TrieNodeBase>();
Char[] rgch = new Char[100];
Action<TrieNodeBase> fn = null;
fn = (TrieNodeBase cur) =>
{
if (stk.Count >= rgch.Length)
{
Char[] tmp = new Char[rgch.Length * 2];
Buffer.BlockCopy(rgch, 0, tmp, 0, rgch.Length * sizeof(Char));
rgch = tmp;
}
foreach (var kvp in cur.CharNodePairs())
{
rgch[stk.Count] = kvp.Key;
TrieNodeBase n = kvp.Value;
stk.Push(n);
if (n.Nodes != null)
fn(n);
else
{
if (n.Value == null) // leaf nodes should always have a value
throw new Exception();
callback(new String(rgch, 0, stk.Count), stk);
}
stk.Pop();
}
};
fn(_root);
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
/// Convert a trie with one value type to another
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public Trie<TNew> ToTrie<TNew>(Func<TValue, TNew> value_converter)
{
Trie<TNew> t = new Trie<TNew>();
DepthFirstTraverse((s,n)=>{
t.Add(s,value_converter(n.Value));
});
return t;
}
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///
///
///
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
public static class TrieExtension
{
public static Trie<TValue> ToTrie<TValue>(this IEnumerable<String> src, Func<String, int, TValue> selector)
{
Trie<TValue> t = new Trie<TValue>();
int idx = 0;
foreach (String s in src)
t.Add(s,selector(s,idx++));
return t;
}
public static Trie<TValue> ToTrie<TValue>(this Dictionary<String, TValue> src)
{
Trie<TValue> t = new Trie<TValue>();
foreach (var kvp in src)
t.Add(kvp.Key, kvp.Value);
return t;
}
public static IEnumerable<TValue> AllSubstringValues<TValue>(this String s, Trie<TValue> trie)
{
return trie.AllSubstringValues(s);
}
public static void AddToValueHashset<TKey, TValue>(this Dictionary<TKey, HashSet<TValue>> d, TKey k, TValue v)
{
HashSet<TValue> hs;
if (d.TryGetValue(k, out hs))
hs.Add(v);
else
d.Add(k, new HashSet<TValue> { v });
}
};
I've just created a Trie implementation in C#:
https://github.com/TomGullen/C-Sharp-Trie/tree/master
Code:
/*
Copyright (c) 2016 Scirra Ltd
www.scirra.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
public class Trie
{
private class Node
{
public bool Terminal { get; set; }
public Dictionary<char, Node> Nodes { get; private set; }
public Node ParentNode { get; private set; }
public char C { get; private set; }
/// <summary>
/// String word represented by this node
/// </summary>
public string Word
{
get
{
var b = new StringBuilder();
b.Insert(0, C.ToString(CultureInfo.InvariantCulture));
var selectedNode = ParentNode;
while (selectedNode != null)
{
b.Insert(0, selectedNode.C.ToString(CultureInfo.InvariantCulture));
selectedNode = selectedNode.ParentNode;
}
return b.ToString();
}
}
public Node(Node parent, char c)
{
C = c;
ParentNode = parent;
Terminal = false;
Nodes = new Dictionary<char, Node>();
}
/// <summary>
/// Return list of terminal nodes under this node
/// </summary>
public IEnumerable<Node> TerminalNodes(char? ignoreChar = null)
{
var r = new List<Node>();
if (Terminal) r.Add(this);
foreach (var node in Nodes.Values)
{
if (ignoreChar != null && node.C == ignoreChar) continue;
r = r.Concat(node.TerminalNodes()).ToList();
}
return r;
}
}
private Node TopNode_ { get; set; }
private Node TopNode
{
get
{
if (TopNode_ == null) TopNode_ = new Node(null, ' ');
return TopNode_;
}
}
private bool CaseSensitive { get; set; }
/// <summary>
/// Get list of all words in trie that start with
/// </summary>
public HashSet<string> GetAutocompleteSuggestions(string wordStart, int fetchMax = 10)
{
if(fetchMax <= 0) throw new Exception("Fetch max must be positive integer.");
wordStart = NormaliseWord(wordStart);
var r = new HashSet<string>();
var selectedNode = TopNode;
foreach (var c in wordStart)
{
// Nothing starting with this word
if (!selectedNode.Nodes.ContainsKey(c)) return r;
selectedNode = selectedNode.Nodes[c];
}
// Get terminal nodes for this node
{
var terminalNodes = selectedNode.TerminalNodes().Take(fetchMax);
foreach (var node in terminalNodes)
{
r.Add(node.Word);
}
}
// Go up a node if not found enough suggestions
if (r.Count < fetchMax)
{
var parentNode = selectedNode.ParentNode;
if (parentNode != null)
{
var remainingToFetch = fetchMax - r.Count;
var terminalNodes = parentNode.TerminalNodes(selectedNode.C).Take(remainingToFetch);
foreach (var node in terminalNodes)
{
r.Add(node.Word);
}
}
}
return r;
}
/// <summary>
/// Initialise instance of trie with set of words
/// </summary>
public Trie(IEnumerable<string> words, bool caseSensitive = false)
{
CaseSensitive = caseSensitive;
foreach (var word in words)
{
AddWord(word);
}
}
/// <summary>
/// Add a single word to the trie
/// </summary>
public void AddWord(string word)
{
word = NormaliseWord(word);
var selectedNode = TopNode;
for (var i = 0; i < word.Length; i++)
{
var c = word[i];
if (!selectedNode.Nodes.ContainsKey(c))
{
selectedNode.Nodes.Add(c, new Node(selectedNode, c));
}
selectedNode = selectedNode.Nodes[c];
}
selectedNode.Terminal = true;
}
/// <summary>
/// Normalise word for trie
/// </summary>
private string NormaliseWord(string word)
{
if (String.IsNullOrWhiteSpace(word)) word = String.Empty;
word = word.Trim();
if (!CaseSensitive)
{
word = word.Trim();
}
return word;
}
/// <summary>
/// Does this word exist in this trie?
/// </summary>
public bool IsWordInTrie(string word)
{
word = NormaliseWord(word);
if (String.IsNullOrWhiteSpace(word)) return false;
var selectedNode = TopNode;
foreach (var c in word)
{
if (!selectedNode.Nodes.ContainsKey(c)) return false;
selectedNode = selectedNode.Nodes[c];
}
return selectedNode.Terminal;
}
}
Example usage:
var trie = new Trie(new String[] {"hello", "help", "he-man", "happy", "hoppy", "tom"});
var autoCompleteSuggestions = trie.GetAutocompleteSuggestions("ha");
foreach (var s in autoCompleteSuggestions)
{
Response.Write(s + "\n");
}
Here is a Trie and a scanner in one (taken from the Resin codebase):
using System;
using System.Collections.Generic;
using System.IO;
namespace Resin
{
public class UseTrie
{
public void Main()
{
var words = new[]{"pre", "prefix"};
var trie = new Trie(words);
// Print "pre" and "prefix"
foreach(var word in trie.GetTokens("pr"))
{
Console.WriteLine(word);
}
}
}
public class Trie
{
public char Value { get; set; }
public bool Eow { get; set; }
public IDictionary<char, Trie> Children { get; set; }
public bool Root { get; set; }
public Trie(bool isRoot)
{
Root = isRoot;
Children = new Dictionary<char, Trie>();
}
public Trie(IList<string> words)
{
if (words == null) throw new ArgumentNullException("words");
Root = true;
Children = new Dictionary<char, Trie>();
foreach (var word in words)
{
AppendToDescendants(word);
}
}
public Trie(string text)
{
if (string.IsNullOrWhiteSpace(text))
{
throw new ArgumentException("text");
}
Value = text[0];
Children = new Dictionary<char, Trie>();
if (text.Length > 1)
{
var overflow = text.Substring(1);
if (overflow.Length > 0)
{
AppendToDescendants(overflow);
}
}
else
{
Eow = true;
}
}
public IEnumerable<string> GetTokens(string prefix)
{
var words = new List<string>();
Trie child;
if (Children.TryGetValue(prefix[0], out child))
{
child.Scan(prefix, prefix, ref words);
}
return words;
}
private void Scan(string originalPrefix, string prefix, ref List<string> words)
{
if (string.IsNullOrWhiteSpace(prefix)) throw new ArgumentException("prefix");
if (prefix.Length == 1 && prefix[0] == Value)
{
// The scan has reached its destination. Find words derived from this node.
if (Eow) words.Add(originalPrefix);
foreach (var node in Children.Values)
{
node.Scan(originalPrefix+node.Value, new string(new []{node.Value}), ref words);
}
}
else if (prefix[0] == Value)
{
Trie child;
if (Children.TryGetValue(prefix[1], out child))
{
child.Scan(originalPrefix, prefix.Substring(1), ref words);
}
}
}
public void AppendToDescendants(string text)
{
if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("text");
Trie child;
if (!Children.TryGetValue(text[0], out child))
{
child = new Trie(text);
Children.Add(text[0], child);
}
else
{
child.Append(text);
}
}
public void Append(string text)
{
if (string.IsNullOrWhiteSpace(text)) throw new ArgumentException("text");
if (text[0] != Value) throw new ArgumentOutOfRangeException("text");
if (Root) throw new InvalidOperationException("When appending from the root, use AppendToDescendants.");
var overflow = text.Substring(1);
if (overflow.Length > 0)
{
AppendToDescendants(overflow);
}
}
}
}
Article at below URI has very good implementation and comparison with other .NET Collection. It also specify scenario where we should use Trie instead of .NET build in collections like (HashSet<>, SortedList<>) etc.
https://visualstudiomagazine.com/articles/2015/10/20/text-pattern-search-trie-class-net.aspx
To get instant suggestions from trie data structure, after loading from strings use the below. (faster retrieval)
public class Trie
{
public struct Letter
{
public const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static implicit operator Letter(char c)
{
c = c.ToString().ToUpper().ToCharArray().First();
return new Letter() { Index = Chars.IndexOf(c) };
}
public int Index;
public char ToChar()
{
return Chars[Index];
}
public override string ToString()
{
return Chars[Index].ToString();
}
}
public class Node
{
public string Word;
public bool IsTerminal { get { return Word != null; } }
public Dictionary<Letter, Node> Edges = new Dictionary<Letter, Node>();
}
public Node Root = new Node();
public Trie(string[] words)
{
for (int w = 0; w < words.Length; w++)
{
var word = words[w];
var node = Root;
for (int len = 1; len <= word.Length; len++)
{
var letter = word[len - 1];
Node next;
if (!node.Edges.TryGetValue(letter, out next))
{
next = new Node();
if (len == word.Length)
{
next.Word = word;
}
node.Edges.Add(letter, next);
}
node = next;
}
}
}
public List<string> GetSuggestions(string word, int max)
{
List<string> outPut = new List<string>();
var node = Root;
int i = 0;
foreach (var l in word)
{
Node cNode;
if (node.Edges.TryGetValue(l, out cNode))
{
node = cNode;
}
else
{
if (i == word.Length - 1)
return outPut;
}
i++;
}
GetChildWords(node, ref outPut, max);
return outPut;
}
public void GetChildWords(Node n, ref List<string> outWords, int Max)
{
if (n.IsTerminal && outWords.Count < Max)
outWords.Add(n.Word);
foreach (var item in n.Edges)
{
GetChildWords(item.Value, ref outWords, Max);
}
}
}
Simple and beautiful:
class Trie
{
private readonly string _key;
private string _value;
private List<Trie> _path;
private List<Trie> _children;
public Trie(string key = "root", string value = "root_val")
{
this._key = key;
this._value = value;
this._path = this._children = new List<Trie>();
}
public void Initialize(Dictionary<string, string> nodes, int keyLength = 1)
{
foreach (var node in nodes)
{
this.Add(node, keyLength);
}
}
public void Add(KeyValuePair<string, string> node, int keyLength = 1)
{
if (this._children.Count == 0 || !this._children.Any(ch => (node.Key.StartsWith(ch._key)) || (ch._key == node.Key)))
{
//For any item that could be a child of newly added item
Predicate<Trie> possibleChildren = (Trie ch) => { return ch._key.StartsWith(node.Key); };
var newChild = new Trie(node.Key, node.Value);
newChild._children.AddRange(this._children.FindAll(possibleChildren));
this._children.RemoveAll(possibleChildren);
this._children.Add(newChild);
}
else
{
this._children.First(ch => (ch._key == node.Key) || (node.Key.Substring(0, keyLength) == ch._key)).Add(node, keyLength + 1);
}
}
public void Delete(string key, bool recursively = true)
{
var newChildren = new List<Trie>(this._children);
foreach (var child in this._children)
{
if (child._key == key)
{
if (!recursively)
{
newChildren.AddRange(child._children);
}
newChildren.Remove(child);
}
else
{
child.Delete(key, recursively);
}
}
this._children = newChildren;
}
public List<Trie> Find(string key, int keyLength = 1)
{
this._path = new List<Trie>();
if (key.Length >= keyLength - 1 && this._key == key.Substring(0, keyLength - 1))
{
this._path.Add(this);
}
foreach (var child in this._children)
{
var childPath = child.Find(key, keyLength + 1);
this._path.AddRange(childPath);
}
return this._path;
}
}
var items = new Dictionary<string, string>
{
{ "a", "First level item" },
{ "b", "First level item"},
{ "ad", "Second level item"},
{ "bv", "Second level item"},
{ "adf", "Third level item"},
{ "adg", "Third level item"},
{ "bvc", "Third level item"},
{ "bvr", "Third level item"}
};
var myTree = new Trie();
myTree.Initialize(items);
Related
I am looking to create a depth tree where each number is connected to two numbers on its left and right on the row below it.
Likewise, each number will be linked to the two numbers on its left and right on the row above it, or just one if it is at an end of its row.
Then I have to calculate the largest sum from top to bottom.
The numbers need to be added dynamically (by a text file) so I cannot add them individually. The format of the text file will look like the image below, taking carriage returns and spaces into consideration. The tree needs to look like this:
I tried to do this a few different ways but I cannot seem to find the best way to do it. I tried 2 dimensional arrays and node trees but I am not proficient enough to do them. Below is a snippet of my Node Tree code that I tried. Please let me know if I need to do anything else here.
public class Node
{
public int value;
public Node left;
public Node right;
public Node parent;
public Node(int value)
{
this.value = value;
}
}
public static Node NewNode(int value)
{
Node node = new Node(value);
node.left = null;
node.right = null;
node.parent = null;
return node;
}
public static void Insert(Node root, Node newNode)
{
if (root == null)
{
root = newNode;
}
else
{
if (root.left == null)
{
root.left = newNode;
newNode.parent = root;
}
else if(root.right == null)
{
root.right = newNode;
newNode.parent = root;
}
else
{
if (root.left.left == null)
{
Insert(root.left, newNode);
}
else
{
Insert(root.right, newNode);
}
}
}
}
public static Node GetTree(string filePath)
{
Node rootNode = null;
string[] lines = File.ReadAllLines(filePath);
if (lines.Length == 0) return null;
foreach (string line in lines)
{
if (string.IsNullOrWhiteSpace(line)) return null;
string[] values = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (values.Length == 0) return null;
foreach (string value in values)
{
int number;
if (!int.TryParse(value, out number)) return null;
}
if (rootNode == null)
{
rootNode = NewNode(int.Parse(values[0]));
}
else
{
Node node = rootNode;
foreach (string value in values)
{
Node newNode = NewNode(int.Parse(value));
Insert(node, newNode);
node = newNode;
}
}
}
return rootNode;
}
Edit: The text file will look similar to this, expecting to have spaces and carriage returns:
3
7 6
2 4 9
1 4 8 2
Structure of Graph.txt (Number of node, Weight of node, left number node, right number node):
(1,3,2,3)
(2,7,4,5)
(3,6,5,6)
(4,2,7,8)
(5,4,8,9)
(6,9,9,10)
(7,1,,)
(8,4,,)
(9,8,,)
(10,2,,)
Code:
public class Node
{
public int Id { get; set; }
public int Weight { get; set; }
public string LeftId { get; set; }
public string RightId { get; set; }
public Node Left { get; set; }
public Node Right { get; set; }
}
internal class Program
{
static void Main(string[] args)
{
var graphDefinition = File.ReadAllText("Graph.txt");
var regex = new Regex(#"\((?<Id>\d*),(?<Weight>\d*),(?<Left>\d*),(?<Right>\d*)\)");
var nodes = new List<Node>();
foreach (Match match in regex.Matches(graphDefinition))
{
nodes.Add(new Node
{
Id = int.Parse(match.Groups["Id"].Value),
Weight = int.Parse(match.Groups["Weight"].Value),
LeftId = match.Groups["Left"].Value,
RightId = match.Groups["Right"].Value
});
}
if (!nodes.Any())
return;
foreach (var node in nodes)
{
if (!string.IsNullOrEmpty(node.LeftId))
node.Left = nodes.FirstOrDefault(p => p.Id == int.Parse(node.LeftId));
if (!string.IsNullOrEmpty(node.RightId))
node.Right = nodes.FirstOrDefault(p => p.Id == int.Parse(node.RightId));
}
var root = nodes.First();
Depth(root, 0);
Console.WriteLine($"result calculation: {CalculatedMax}");
}
private static int CalculatedMax = int.MinValue;
private static void Depth(Node node, int currentSum)
{
if (node.Left == null && node.Right == null)
{
CalculatedMax = Math.Max(CalculatedMax, currentSum + node.Weight);
return;
}
Depth(node.Left, currentSum + node.Weight);
Depth(node.Right, currentSum + node.Weight);
}
}
Use table for input. Minus 1 is a node with no child. The table could be rows in a csv file.
After some thinking I realize you can build the tree from an array of numbers. You first create all the nodes in a list NODES with the values. Then you link the list into the binary tree.
class Program
{
static void Main(string[] args)
{
int[] data = { 3, 7, 6, 2, 4, 9, 1, 4, 8, 2 };
Node root = Node.BuildTree(data);
}
}
public class Node
{
int value { get; set; }
Node left { get; set; }
Node right { get; set; }
static List<Node> nodes { get; set; }
public static Node BuildTree(int[] input)
{
nodes = new List<Node>();
foreach(int i in input)
{
Node node = new Node();
node.left = null;
node.right = null;
node.value = i;
nodes.Add(node);
}
Node root = nodes[0];
int start = 0;
int row = 0;
while(start < nodes.Count)
{
int end = row + start;
for (int i = start; i < Math.Min(end + 1, nodes.Count); i++)
{
int col = i - start;
int leftChild = (end + 1 + col) < nodes.Count ? end + 1 + col : -1;
int rightChild = (end + 2 + col) < nodes.Count ? end + 2 + col : -1;
Console.WriteLine("row = {0}, col = {1}, left = {2}, right = {3}, start = {4}, end = {5}", row, col, leftChild, rightChild,start, end);
nodes[i].left = (leftChild == -1) ? null : nodes[leftChild];
nodes[i].right = (rightChild == -1) ? null : nodes[rightChild];
}
start = end + 1;
row++;
}
return root;
}
}
I am trying to do a simple inorder traversal of a BST and the BST builds properly but when I try to print the BST inorder it goes to the first left node and then doesn't go to any other nodes after that and creates an overflow.
Ive tried to do different inorder traversals with getLeft and getRight but it is still doing the same thing
class Program
{
static void Main(string[] args)
{
Tree tree = new Tree();
List<int> rands = new List<int>();
Random random = new Random();
int between = random.Next(20, 30);
for (int i = 0; i < between; i++)
{
rands.Add(random.Next(100));
}
for (int x = 0; x < rands.Count; x++)
{
tree.constructTree(rands[x]);
}
tree.Inorder(tree.returnRoot());
}
class Node
{
private int number;
public Node left;
public Node right;
public Node()
{
}
public Node getLeft()
{
return this.left;
}
public Node getRight()
{
return this.right;
}
public int GetSetNumber
{
get
{
return this.number;
}
set
{
this.number = value;
}
}
public Node GetSetLeft
{
get
{
return this.left;
}
set
{
this.left = value;
}
}
public Node GetSetRight
{
get
{
return this.right;
}
set
{
this.right = value;
}
}
}
class Tree
{
public Node root;
public Node returnRoot()
{
return this.root;
}
public void constructTree(int num)
{
Node t = new Node();
t.GetSetNumber = num;
if (root == null)
{
root = t;
}
else
{
Node cur = root;
Node top;
while (true)
{
top = cur;
if (num < top.GetSetNumber)
{
cur = cur.GetSetLeft;
if (cur == null)
{
top.GetSetLeft = t;
return;
}
}
else
{
cur = cur.GetSetRight;
if (cur == null)
{
top.GetSetRight = t;
return;
}
}
}
}
}
public void Inorder(Node Root)
{
if (root == null)
{
return;
}
Inorder(root.left);
Console.WriteLine(root.GetSetNumber + " ");
Inorder(root.right);
}
}
You are referencing root in Inorder, not Root. root (lower-case r) is the class variable containing the root of the entire tree, not the Node parameter you have passed in. Your code loops infinitely because you are calling Inorder on the same node forever.
If you capitalize your references to root in Inorder (or use a different variable name in the method to avoid confusion, like current) you should be able to make some progress.
public void Inorder(Node Root)
{
if (Root == null)
{
return;
}
Inorder(Root.left);
Console.WriteLine(Root.GetSetNumber + " ");
Inorder(Root.right);
}
This is my implementation for BST (Binary Search Tree). Can Anyone help me to create two methods, one to Connect Leafs and one to return a List of Nodes around the Tree, for example: Connecting Leaf Example In this picture it shows how the leafs should be connected, Nodes that should be stored in List and the way the nodes stored in List need to be in this way where the root is the first element and going to the left passing down to leafs going back to root from the right. In my example it should be 8(root), 3, 1, 4, 7, 13, 14, 10, 8(root).
Thank You!
**class Node
{
private int VL;
private int Niv;
public Node Parent, LC, RC;
public Node()
{
this.Parent = this.LC = this.RC = null;
this.Niv = -1;
}
public Node(int x)
{
this.VL = x;
this.Parent = this.LC = this.RC = null;
this.Niv = -1;
}
public int Vlera
{
get { return this.VL; }
set { this.VL = value; }
}
public int Niveli
{
get { return this.Niv; }
set { this.Niv = value; }
}
}
class BSTree
{
public Node Root;
private int MaxNiv;
public BSTree()
{
this.Root = null;
this.MaxNiv = -1;
}
public void Insert(int x)
{
Node tmp = new Node(x);
if (this.Root == null)
{
tmp.Niveli = 0;
this.Root = tmp;
}
else InsertNode(tmp);
if (tmp.Niveli > this.MaxNiv) MaxNiv = tmp.Niveli;
}
public void ConnectLeafs()
{
//TODO
}
public List<T> ReturnNodesAroundTheTree()
{
//TODO
}
public Node GoTo_Node(Node nd)
{
return GoTo_Node_Rec(this.Root, nd);
}
public Node GoTo_Node(int x)
{
return GoTo_Node_Rec(this.Root, x);
}
private Node GoTo_Node_Rec(Node root, Node nd)
{
if (root.Vlera == nd.Vlera) return root;
if (root.Vlera > nd.Vlera) return GoTo_Node_Rec(root.LC, nd);
else return GoTo_Node_Rec(root.RC, nd);
}
private Node GoTo_Node_Rec(Node root, int x)
{
if (root.Vlera == x) return root;
if (root.Vlera > x) return GoTo_Node_Rec(root.LC, x);
else return GoTo_Node_Rec(root.RC, x);
}
private void InsertNode(Node nd)
{
Node tmp = InsertRecNode(this.Root, nd.Vlera);
if (nd.Vlera >= tmp.Vlera) tmp.RC = nd;
else tmp.LC = nd;
nd.Parent = tmp;
nd.Niveli = nd.Parent.Niveli++;
//if (nd.Niveli > this.MaxNiv) MaxNiv = nd.Niveli;
}
private Node InsertRecNode(Node root, int x)
{
if (x >= root.Vlera)
if (root.RC != null) return InsertRecNode(root.RC, x);
else return root;
else
if (root.LC != null) return InsertRecNode(root.LC, x);
else return root;
}
private bool IsRoot(Node nd)
{
if (nd.Parent == null) return true;
return false;
}
private bool IsLeaf(Node nd)
{
if (nd.LC == null && nd.RC == null) return true;
return false;
}**
Here is the easy way to do this. I created a List of all the node. When you create a new node add node to list. See code below
class BSTree
{
public Node Root;
private int MaxNiv;
private List<Node> nodes = new List<Node>();
public BSTree()
{
this.Root = null;
this.MaxNiv = -1;
}
public void Insert(int x)
{
Node tmp = new Node(x);
nodes.Add(tmp);
if (this.Root == null)
{
tmp.Niveli = 0;
this.Root = tmp;
}
else InsertNode(tmp);
if (tmp.Niveli > this.MaxNiv) MaxNiv = tmp.Niveli;
}
public void ConnectLeafs()
{
//TODO
}
public List<Node> ReturnNodesAroundTheTree()
{
return nodes.Where(x => IsLeaf(x)).ToList();
}
}
I have following code:
public string Longest
{
get
{
int min = int.MinValue;
string longest = "";
for (Node i = Head; i != null; i = i.Next)
{
if (i.Text.Length > min)
{
longest = i.Text.Length.ToString();
}
return longest;
}
return longest;
}
}
The problem is I have those strings:
List text = new List();
text.Add("Petar");
text.Add("AHS");
text.Add("Google");
text.Add("Me");
When I try out the propertie it says that the longest string is 5 but thats not true the longest string is six. I've tried to find out where my problem but i coulnd't find it.
Your code has a couple of problems:
A length can be, as minimum, 0, so you don't need to use int.MinValue
You are returning on the first iteration
You are not updating min after finding a longer value
You are returning the length of the string, not the string itself
Your code should look like this:
public string Longest
{
get
{
int longestLength = 0;
string longestWord = string.Empty;
for (Node i = Head; i != null; i = i.Next)
{
if (i.Text.Length > longestLength)
{
longestLength = i.Text.Length;
longestWord = i.Text;
}
}
return longestWord;
}
}
If what you want to return is the maximum length instead of the word with the maximum length, your property is both wrongly named and typed, and it should look like this instead:
public int MaximumLength
{
get
{
int maximumLength = 0;
for (Node i = Head; i != null; i = i.Next)
{
if (i.Text.Length > maximumLength)
{
maximumLength = i.Text.Length;
}
}
return maximumLength;
}
}
If you have an IEnumerable<string> then do the following
var list = new List<string>();
list.Add("AAA");
list.Add("AAAAA");
list.Add("A");
list.Add("AAAA");
list.Add("AAAAAA");
list.Add("AA");
// max has the longest string
var max = list.Aggregate(string.Empty,
(bookmark, item) => item.Length>bookmark.Length ? item : bookmark);
or using a loop
string max = string.Empty;
int length=0;
foreach(var item in list)
{
if(item.Length>length)
{
max = item;
length = item.Length;
}
}
But it appears you have a linked list which I recreated as a skeleton below:
public class Node
{
public Node(string text)
{
this.Text = text;
this.Head = this;
}
public Node(Node parent, string text): this(text)
{
if(parent!=null)
{
parent.Next = this;
this.Head = parent.Head;
}
}
public Node Head { get; }
public Node Next { get; set; }
public string Text { get; }
public Node Add(string text) => new Node(this, text);
}
and finding the longest string with a loop is
var list = new Node("AAA");
list = list.Add("AAAAA");
list = list.Add("A");
list = list.Add("AAAA");
list = list.Add("AAAAAA");
list = list.Add("AA");
string max = list.Text;
int length = max.Length;
for(Node node = list.Head; node != null; node = node.Next)
{
if(node.Text.Length > length)
{
max = node.Text;
length= node.Text.Length;
}
}
// max has the longest string
Edit 1
I took the linked list and made it IEnumerable<string> by moving your loop code into a method:
public class Node : IEnumerable<string>
{
public Node(string text)
{
this.Text = text;
this.Head = this;
}
public Node(Node parent, string text) : this(text)
{
if(parent!=null)
{
parent.Next = this;
this.Head = parent.Head;
}
}
public Node Head { get; }
public Node Next { get; set; }
public string Text { get; }
public Node Add(string text) => new Node(this, text);
public IEnumerator<string> GetEnumerator()
{
// Loop through the list, starting from head to end
for(Node node = Head; node != null; node = node.Next)
{
yield return node.Text;
}
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
and now I can use a single LINQ statement
var list = new Node("AAA");
list = list.Add("AAAAA");
list = list.Add("A");
list = list.Add("AAAA");
list = list.Add("AAAAAA");
list = list.Add("AA");
// max has the longest string
var max = list.Aggregate(string.Empty,
(bookmark, item) => item.Length>bookmark.Length ? item : bookmark);
I'm creating an application in Unity3d that communicates with python's websockets library. My python script is as following:
from __future__ import division
import asyncio
import websockets
import time
import os
from threading import Thread
from random import randint
from read import CustOPCLib
import socket
from jsonsocket import Client,Server
class SubHandler(object):
def data_change(self, handle, node, val, attr):
print("Python: New data change event", handle, node, val, attr)
def datachange_notification(self, node, val, data):
print("Data received: ",val)
def event(self, handle, event):
print("Python: New event", handle, event)
p = CustOPCLib()
async def hello(websocket, path):
p.connect() #my own custom library
while True:
datastring = p.opcjson() #this is a jsonstring
await websocket.send(datastring)
#print("> {}".format(datastring))
time.sleep(1)
if __name__ == '__main__':
start_server = websockets.serve(hello, '127.0.0.1', 8765)
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()
my json string is as following:
{
"Index": 709953575,
"Moto": true,
"Start": false,
"StartWINCC": false,
"Stop": false,
"StopWINCC": false,
"Tag1": true,
"Tag2": false
}
This is the string i want to send to Unity. In Unity3d I've made the following script that used the Concurrentqueue from mono. The script works accordingly, the problem i have however, is that i get alot of null values from the websocket.
my Unity3d script:
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Threading;
public class ConcurrentQueue<T> : IEnumerable<T>, ICollection, ISerializable, IDeserializationCallback
{
class Node
{
public T Value;
public Node Next;
}
Node _head = new Node();
Node _tail;
int _count;
/// <summary>
/// </summary>
public ConcurrentQueue()
{
_tail = _head;
}
public ConcurrentQueue(IEnumerable<T> enumerable)
: this()
{
foreach (T item in enumerable)
Enqueue(item);
}
public void Enqueue(T item)
{
var node = new Node { Value = item };
Node oldTail = null;
bool update = false;
while (!update)
{
oldTail = _tail;
var oldNext = oldTail.Next;
// Did tail was already updated ?
if (_tail == oldTail)
{
if (oldNext == null)
{
// The place is for us
update = Interlocked.CompareExchange(ref _tail.Next, node, null) == null;
}
else
{
// another Thread already used the place so give him a hand by putting tail where it should be
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
}
}
}
// At this point we added correctly our node, now we have to update tail. If it fails then it will be done by another thread
Interlocked.CompareExchange(ref _tail, node, oldTail);
Interlocked.Increment(ref _count);
}
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryDequeue(out T value)
{
value = default(T);
bool advanced = false;
while (!advanced)
{
Node oldHead = _head;
Node oldTail = _tail;
Node oldNext = oldHead.Next;
if (oldHead == _head)
{
// Empty case ?
if (oldHead == oldTail)
{
// This should be false then
if (oldNext != null)
{
// If not then the linked list is mal formed, update tail
Interlocked.CompareExchange(ref _tail, oldNext, oldTail);
}
value = default(T);
return false;
}
else
{
value = oldNext.Value;
advanced = Interlocked.CompareExchange(ref _head, oldNext, oldHead) == oldHead;
}
}
}
Interlocked.Decrement(ref _count);
return true;
}
/// <summary>
/// </summary>
/// <returns></returns>
public bool TryPeek(out T value)
{
if (IsEmpty)
{
value = default(T);
return false;
}
Node first = _head.Next;
value = first.Value;
return true;
}
public void Clear()
{
_count = 0;
_tail = _head = new Node();
}
IEnumerator IEnumerable.GetEnumerator()
{
return InternalGetEnumerator();
}
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return InternalGetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return InternalGetEnumerator();
}
IEnumerator<T> InternalGetEnumerator()
{
Node myHead = _head;
while ((myHead = myHead.Next) != null)
{
yield return myHead.Value;
}
}
void ICollection.CopyTo(Array array, int index)
{
T[] dest = array as T[];
if (dest == null)
return;
CopyTo(dest, index);
}
public void CopyTo(T[] dest, int index)
{
IEnumerator<T> e = InternalGetEnumerator();
int i = index;
while (e.MoveNext())
{
dest[i++] = e.Current;
}
}
public T[] ToArray()
{
T[] dest = new T[_count];
CopyTo(dest, 0);
return dest;
}
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
throw new NotImplementedException();
}
bool ICollection.IsSynchronized
{
get { return true; }
}
public void OnDeserialization(object sender)
{
throw new NotImplementedException();
}
readonly object _syncRoot = new object();
object ICollection.SyncRoot
{
get { return _syncRoot; }
}
public int Count
{
get
{
return _count;
}
}
public bool IsEmpty
{
get
{
return _count == 0;
}
}
}
public class test : MonoBehaviour
{
class OpcJson
{
public int Index { get; set; }
public bool Moto { get; set; }
public bool Start { get; set; }
public bool StartWINCC { get; set; }
public bool Stop { get; set; }
public bool StopWINCC { get; set; }
public bool Tag1 { get; set; }
public bool Tag2 { get; set; }
}
//variables
static readonly ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public string receivedFromServer;
WebSocket w = new WebSocket(new Uri("ws://127.0.0.1:8765"));
public Text testert;
public Image moto;
public Image start;
public Image startwincc;
public Image stop;
public Image stopwincc;
public Image tag1;
public Image tag2;
// Use this for initialization
IEnumerator StartWebsocket()
{
yield return StartCoroutine(w.Connect());
//w.SendString("Hi there");
//int i = 0;
while (true)
{
string reply = w.RecvString();
if (reply != null)
{
//Debug.Log(reply);
queue.Enqueue(reply);
//receivedFromServer = reply;
//Debug.Log("Received: " + reply);
//w.SendString("Hi there" + i++);
}
if (w.error != null)
{
Debug.LogError("Error: " + w.error);
break;
}
yield return 0;
}
w.Close();
}
private void OnApplicationQuit()
{
StopAllCoroutines();
w.Close();
}
IEnumerator JsonObjectSetter(float waitforsecods)
{
while (true)
{
queue.TryDequeue(out receivedFromServer);
//string s = receivedFromServer;
//Debug.Log(s);
if(receivedFromServer == null)
{
Debug.Log("I'm null");
}
else
{
var results = JsonConvert.DeserializeObject<OpcJson>(receivedFromServer);
testert.text = results.Index.ToString();
if (results.Moto == true)
{
moto.GetComponent<Image>().color = Color.green;
}
else
{
moto.GetComponent<Image>().color = Color.red;
}
if (results.Start == true)
{
start.GetComponent<Image>().color = Color.green;
}
else
{
start.GetComponent<Image>().color = Color.red;
}
if (results.StartWINCC == true)
{
startwincc.GetComponent<Image>().color = Color.green;
}
else
{
startwincc.GetComponent<Image>().color = Color.red;
}
if (results.Stop == true)
{
stop.GetComponent<Image>().color = Color.green;
}
else
{
stop.GetComponent<Image>().color = Color.red;
}
if (results.StopWINCC == true)
{
stopwincc.GetComponent<Image>().color = Color.green;
}
else
{
stopwincc.GetComponent<Image>().color = Color.red;
}
if (results.Tag1 == true)
{
tag1.GetComponent<Image>().color = Color.green;
}
else
{
tag1.GetComponent<Image>().color = Color.red;
}
if (results.Tag2 == true)
{
tag2.GetComponent<Image>().color = Color.green;
}
else
{
tag2.GetComponent<Image>().color = Color.red;
}
}
yield return new WaitForSeconds(waitforsecods);
}
}
private void Start()
{
StartCoroutine(StartWebsocket());
StartCoroutine(JsonObjectSetter(1));
}
}
as you can see, I've made an if/else statement in my JsonObjectSetter method. Everytime the string is null after a dequeue, it prints out "I'm null", and if its not null, it gets used to set an image to a color according to the value.
How can i make it so I won't get any nulls anymore?
Edit 1: during a 7-minute test I've counted 49 nulls. This is quite a big issue to be honest...
Fixed it!
The problem was that my python script had a time.sleep() which lasts 1 second, changed it to 0.1, and changed the WaitForSecods in the Unityscript to 0.25f. This totally fixed my problem. Kind of stupid that I didn't think of this before posting it on Stackoverflow.