0

I have

public class Letter
{
    public string Value;
    public int Id;

    public Letter(string val, int id)
    {
        this.Value = val;
        this.Id = id;
    }
}

I need a kind of duplicate dictionary (LookUp(?)) for:

private something TestCollection()
{
    List<Letter> inputList = new List<Letter> { 
        new Letter("a", 9), 
        new Letter("b", 5), 
        new Letter("c", 8), 
        new Letter("aIdentic", 9) 
    };

    // compare inputList by letter's ID(!)
    // use inputList (zero based) INDEXES as values

    // return something, like LookUp: { "a"=>(0, 3), "b"=>(1), "c"=>(2) };

}

using .NET 4

How to obtain it?

As I understand, there is 2 solutions, one from .NET 4, Lookup<Letter, int>, other, classic one Dictionary<Letter, List<int>>

thanks.

EDIT:

For output. There is 2 letters "a", identified by ID 9 on index "0" in the array(first position). "b" have index 1 (second position in the input array), "c" - index 2 (is third).

EDIT 2

John solution:

    public class Letter
    {
        public string Value;
        public int Id;

        public Letter(string val, int id)
        {
            this.Value = val;
            this.Id = id;
        }
    }

    private void btnCommand_Click(object sender, EventArgs e)
    {
        List<Letter> inputList = new List<Letter> { 
            new Letter("a", 9), 
            new Letter("b", 5), 
            new Letter("c", 8), 
            new Letter("aIdentic", 9) 
        };

        var lookup = inputList.Select((value, index) =>
            new { value, index }).ToLookup(x => x.value, x => x.index);

        // outputSomething { "a"=>(0, 3), "b"=>(1), "c"=>(2) };
        foreach (var item in lookup)
        {
            Console.WriteLine("{0}: {1}", item.Key, item.ToString());
        }

    }

Output (I expect no more than 3 keys):

//WindowsFormsApplication2.Form1+Letter: System.Linq.Lookup`2+Grouping[WindowsFormsApplication2.Form1+Letter,System.Int32]
//WindowsFormsApplication2.Form1+Letter: System.Linq.Lookup`2+Grouping[WindowsFormsApplication2.Form1+Letter,System.Int32]
//WindowsFormsApplication2.Form1+Letter: System.Linq.Lookup`2+Grouping[WindowsFormsApplication2.Form1+Letter,System.Int32]
//WindowsFormsApplication2.Form1+Letter: System.Linq.Lookup`2+Grouping[WindowsFormsApplication2.Form1+Letter,System.Int32]

EDIT 3 Equals

public override bool Equals(object obj)
{
    if (obj is Letter)
        return this.Id.Equals((obj as Letter).Id);
    else
        return base.Equals(obj);
}

public override int  GetHashCode()
{
    return this.Id;
}
serhio
  • 28,010
  • 62
  • 221
  • 374
  • What is wrong with your last example i.e. a dictionary of dictionaries? Did you try it? It sounds like you need multiple values per key, not multiple keys per value as the question suggests. – Tim Lloyd Jan 24 '11 at 15:50
  • @chibacity: yes. There are multiple keys in the dictionary, so to each key corresponds an array of values. – serhio Jan 24 '11 at 15:54
  • @serhio A dictionary of lists is a good solution then. A single key can refer to a list with multiple items in. – Tim Lloyd Jan 24 '11 at 15:55
  • @chibacity: maybe. The question is how to obtain it :) – serhio Jan 24 '11 at 15:57
  • @serhio I'm afraid 'obtain it' is not entirely clear. What problem are you having exactly? – Tim Lloyd Jan 24 '11 at 15:58
  • You've *nearly* copied my code, but not quite enough. `x => x.value` should be `x => x.value.Id` – Jon Skeet Jan 24 '11 at 16:43

1 Answers1

1

Lookup is probably the right class to use here - and LINQ lets you build one with ToLookup. Note that Lookup was introduced in .NET 3.5, not .NET 4.

Having said that, it's not at all clear how you'd go from your input to your sample output...

EDIT: Okay, now that I understand you're after the index, you might want to use the overload of Select which includes an index first:

var lookup = inputList.Select((value, index) => new { value, index })
                      .ToLookup(x => x.value.Id, x => x.index);
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • i know that such a function exist, however don't know exactly how to apply in my case. A litte example would be cool. – serhio Jan 24 '11 at 16:00
  • @serhio: Well, your example is far from clear - I can't see how you'd get from your sample input to your sample output - but I suspect that `inputList.ToLookup(x => x.Id, x => x.Value)` is what you're after. I strongly suggest that you take a few hours to read a LINQ tutorial though - it's not a great topic to pick up in this sort of way. – Jon Skeet Jan 24 '11 at 16:02
  • 1
    @serhio: Ah, by index. So the value is irrelevant? That would have been useful to make clearer... will edit my answer. – Jon Skeet Jan 24 '11 at 16:06
  • @serhio: See my edit for a suggestion. But should the "aIdentic" be "a" in your question? – Jon Skeet Jan 24 '11 at 16:08
  • yes. "a" == "aIdentic" See the output. I expect 3 keys, not 4 as we have, concretly the following LetterWithId=9, LetterWithId=5 and LetterWithId=8 – serhio Jan 24 '11 at 16:30
  • @serhio: In what way is "a" == "aIdentic"? They're completely different strings. Was it a typo in the question, or did you forget to tell us how to compare IDs? – Jon Skeet Jan 24 '11 at 16:35
  • @Jon. Say I have x=Letter("a", 10) and y=Letter("a", 11). then x != y. Say I have x=Letter("something", 14) and y=Letter("Something", 14), then x == y. *if Ids are the same, two instances should be considered as the same key*. So, Letter("abc", 1) == Letter("xyz", 1), because the Ids 1 == 1 – serhio Jan 24 '11 at 16:41
  • 1
    @serhio: Ah, I've got it - I hadn't read that the 9 is the ID, not the "a". With you now. I'm used to IDs usually being expressed *before* values... and for "Letter" I'd expected a textual ID. Having said that, my answer is still appropriate - your sample code uses `x => x.value`, not `x => x.value.Id` like mine does. – Jon Skeet Jan 24 '11 at 16:41
  • "Letter" is just a class name. it does represent a "Foo" for this example. – serhio Jan 24 '11 at 16:43
  • 1
    @serhio: "Foo" would actually have been clearer, to be honest - it wouldn't have suggested as strong a correlation between the textual part and its ID. (I hope your real code doesn't use public fields, mind you...) – Jon Skeet Jan 24 '11 at 16:45
  • @Jon, I agree, that Foo would be more clear :) this works. thanks! No real code does not use public fields :)) – serhio Jan 24 '11 at 16:46
  • 1
    @serhio: Because the result isn't a `Lookup` - it's a `Lookup`. Your ID is of type `int`, not `Letter`. If you want to be able to look up by `Letter`, you can get rid of the ".ID" and implement `IEquatable` in `Letter` itself (or just override Equals and GetHashCode). – Jon Skeet Jan 24 '11 at 16:59
  • Just last thing. Why does `Lookup mLookup = (lookup as Lookup);` return null? I need "letters"=>"idexes", not "letter Ids" => "indexes"... ok. ok. understood. – serhio Jan 24 '11 at 17:00
  • @serhio: `IEquatable` *will* help, if you implement it properly - but that includes overriding GetHashCode. – Jon Skeet Jan 24 '11 at 17:07
  • equals + GetHashCode Worked :) I wrote the code in the Edit 3 – serhio Jan 24 '11 at 17:13
  • @serhio: Your Equals implementation is far from ideal. There are lots of other questions on SO about how to implement it though - I suggest you do a bit of research on the topic. – Jon Skeet Jan 24 '11 at 17:36