user1930254
user1930254

Reputation: 1321

c# collection type, to keep index order

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

Answers (3)

participant
participant

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:

  1. from 2, 1, 1 create a HashSet (2, 1)
  2. lookup (2, 1) in the Dictionary -> ((1, 0.39785), (2, 0.2043))
  3. with a partial key lookup a double like 2 -> 0.2043

CAVEAT 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

PJ7
PJ7

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

Fratyx
Fratyx

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

Related Questions