Reputation: 1321
I have a file with rows keys values
-----+---------------------------
1 1 2 0.39785 0.39785 0.2043 36
1 1 3 0.409604 0.409604 0.180792 24
1 1 4 0.407281 0.407281 0.185438 24
1 1 5 0.404958 0.404958 0.190084 24
1 1 6 0.403399 0.403399 0.193203 24
...
23 34 36 0.414457 0.354921 0.230622 576
..
-the first 3 numbers are keys and represent a matchup, they are unique, and they are ascending
-the float values are linked to the keys. eg: first row's 4th element (0.39785) belongs to key 1, 6th element (0.2043) to 2.
I read it line by line and split it by " " (space). How should I store it (which collection/structure).
Lets say I want to lookup "2 1 1". As I wrote keys are ascending, there won't be an entry like "2 1 1", only "1 1 2", so first I have to sort it, but I want to get the values in the lookup's order (0.2043 0.39785 0.39785).
Upvotes: 3
Views: 455
Reputation: 3003
The data-structure below should meet all your requirements:
Dictionary<HashSet<int>, Dictionary<int, double>>
It should be easy to create an instance of the above structure with LINQ from your original data.
Access should be easy:
HashSet
(2, 1)Dictionary
-> ((1, 0.39785), (2, 0.2043))double
like 2 -> 0.2043CAVEAT The solution will only work as long as for identical int
-values on one line the double
-values are identical as well. (Which seems to hold true for the provided sample-data).
EDIT The code to create yourLookup
:
List<List<int>> intList = new List<List<int>>() {
new List<int> () {1, 1, 2},
new List<int> () {1, 1, 3},
...
};
List<List<double>> doubleList = new List<List<double>> {
new List<double>() {0.39785, 0.39785, 0.2043},
new List<double>() {0.409604, 0.409604, 0.180792},
....
};
var dictionaries = intList.Zip(doubleList, (Is, Ds) =>
{ return Is.Zip(Ds, (i, d) => new KeyValuePair<int, double>(i, d)).Distinct()
.ToDictionary(kv => kv.Key, kv => kv.Value); });
var yourLookup = dictionaries.Select(
dictionary => new { hashset = new HashSet<int>(dictionary.Keys), dictionary })
.ToDictionary(x => x.hashset, x => x.dictionary);
Upvotes: 2
Reputation: 787
[TestMethod]
public void test()
{
var data = new string[]{
"1 1 2 0.39785 0.39785 0.2043 36",
"1 1 3 0.409604 0.409604 0.180792 24",
"1 1 4 0.407281 0.407281 0.185438 24",
"1 1 5 0.404958 0.404958 0.190084 24",
"1 1 6 0.403399 0.403399 0.193203 24"
};
var dic = new FloatLookup(data);
var test1 = dic.GetValues(211).ToArray();
CollectionAssert.AreEquivalent(new float[] { 0.39785F, 0.39785F, 0.2043F }, test1);
var test2 = dic.GetValues(121).ToArray();
CollectionAssert.AreEquivalent(new float[] { 0.39785F, 0.2043F, 0.39785F }, test2);
var test3 = dic.GetValues(611).ToArray();
CollectionAssert.AreEquivalent(new float[] { 0.193203F, 0.403399F, 0.403399F }, test3);
}
class FloatLookup
{
Dictionary<int, KeyValuePair<int, float>[]> dic;
public FloatLookup(string[] data)
{
dic = data.Select(GetKeyValuePair).
ToDictionary(o => o.Key, o => o.Value);
}
public IEnumerable<float> GetValues(int num)
{
return GetValues(GetInts(num));
}
public IEnumerable<float> GetValues(IEnumerable<int> ints)
{
var key = GetKey(ints);
KeyValuePair<int, float>[] kvps = null;
if (!dic.TryGetValue(key, out kvps))
yield break;
foreach (var i in ints)
yield return kvps.First(o => o.Key == i).Value;
}
static KeyValuePair<int, KeyValuePair<int, float>[]> GetKeyValuePair(string line)
{
var items = line.Split(' ');
var ints = new string[] { items[0], items[1], items[2] }.
Select(o => int.Parse(o)).ToArray();
var floats = new string[] { items[3], items[4], items[5] }.
Select(o => float.Parse(o)).ToArray();
var kvps = Enumerable.Range(0, 3).Select(o =>
new KeyValuePair<int, float>(ints[o], floats[o])).Distinct().ToArray();
var key = GetKey(ints);
return new KeyValuePair<int, KeyValuePair<int, float>[]>(key, kvps);
}
static int[] GetInts(int num)
{
return num.ToString().ToCharArray().Select(o =>
int.Parse(o.ToString())).ToArray();
}
static int GetKey(IEnumerable<int> ints)
{
var ret = 0;
var ary = ints.ToArray();
Array.Sort(ary);
var c = 1;
for (int i = ary.GetUpperBound(0); i > -1; i--)
{
ret += ary[i] * c;
c *= 10;
}
return ret;
}
Upvotes: 0
Reputation: 5797
Interesting problem. I created this class:
class Mapper
{
public void Add(int n1, int n2, int n3, double f1, double f2, double f3)
{
int[] intArray = new int[] {n1,n2, n3};
Array.Sort(intArray);
Dictionary<int, double> dict = new Dictionary<int, double>();
dict[n1] = f1;
dict[n2] = f2;
dict[n3] = f3;
myDictionary[string.Join("_", intArray.Select(i=>i.ToString()))] = dict;
}
public Tuple<double, double, double> Find(int n1, int n2, int n3)
{
string key = CreateKey(n1, n2, n3);
if (!myDictionary.ContainsKey(key))
return null;
Dictionary<int, double> found = myDictionary[key];
return new Tuple<double, double, double>(found[n1], found[n2], found[n3]);
}
private string CreateKey(int n1, int n2, int n3)
{
int[] intArray = new int[] { n1, n2, n3 };
Array.Sort(intArray);
return string.Join("_", intArray.Select(i => i.ToString()));
}
private Dictionary<string, Dictionary<int, double>> myDictionary = new Dictionary<string, Dictionary<int, double>>();
}
By adding the 6-tuple in Add
it sorts the integers and joins them to the unique key string (e.g. 1_1_2). The doubles are inserted in a lookup dictionary. Some keys may be set here multiple times but as they the int->double associations are identical in one line it doesn't matter.
Accessing in Find
happens in a corresponding way.
Upvotes: 0