3

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).

4
  • 3
    It sound like you want to put it into a Dictionary<Tuple<int,int,int>>,Tuple<float,float,float>>. Ie you lookup a triad of ints and get back a triad of floats. Commented Oct 9, 2014 at 18:57
  • @tolanj That may be a start, but it doesn't address the sorting and equality (1, 1, 2 == 1, 2, 1 == 2, 1, 1) requirements. Commented Oct 9, 2014 at 19:06
  • There's not going to be a built-in collection to do this. You'll need to create a custom class for your dictionary key that supports equality when the keys are in any order, and create a "lookup" method that will return the values in the order that the sub-keys are provided. Commented Oct 9, 2014 at 19:08
  • 1
    @D Stanley indeed, I lean towards @participant's answer, but a Dictionary as above could be inherited or wrapped with basic input / output sorting routines on the accessor methods. Commented Oct 10, 2014 at 8:38

3 Answers 3

2

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);
Sign up to request clarification or add additional context in comments.

Comments

0

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.

Comments

0
[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;
    }

1 Comment

This is in a wide class of problems you can do in your sleep if you've ever played with Project Euler. I highly recommend you take a look and use it periodically to sharpen your coding claws. projecteuler.net

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.