{"action":"created","issue":{"url":"https://api.github.com/repos/dotnet/corefxlab/issues/446","labels_url":"https://api.github.com/repos/dotnet/corefxlab/issues/446/labels{/name}","comments_url":"https://api.github.com/repos/dotnet/corefxlab/issues/446/comments","events_url":"https://api.github.com/repos/dotnet/corefxlab/issues/446/events","html_url":"https://github.com/dotnet/corefxlab/issues/446","id":116856755,"number":446,"title":"Consider adding a Bidirectional Dictionary","user":{"login":"ianhays","id":2606879,"avatar_url":"https://avatars.githubusercontent.com/u/2606879?v=3","gravatar_id":"","url":"https://api.github.com/users/ianhays","html_url":"https://github.com/ianhays","followers_url":"https://api.github.com/users/ianhays/followers","following_url":"https://api.github.com/users/ianhays/following{/other_user}","gists_url":"https://api.github.com/users/ianhays/gists{/gist_id}","starred_url":"https://api.github.com/users/ianhays/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ianhays/subscriptions","organizations_url":"https://api.github.com/users/ianhays/orgs","repos_url":"https://api.github.com/users/ianhays/repos","events_url":"https://api.github.com/users/ianhays/events{/privacy}","received_events_url":"https://api.github.com/users/ianhays/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":{"login":"ianhays","id":2606879,"avatar_url":"https://avatars.githubusercontent.com/u/2606879?v=3","gravatar_id":"","url":"https://api.github.com/users/ianhays","html_url":"https://github.com/ianhays","followers_url":"https://api.github.com/users/ianhays/followers","following_url":"https://api.github.com/users/ianhays/following{/other_user}","gists_url":"https://api.github.com/users/ianhays/gists{/gist_id}","starred_url":"https://api.github.com/users/ianhays/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ianhays/subscriptions","organizations_url":"https://api.github.com/users/ianhays/orgs","repos_url":"https://api.github.com/users/ianhays/repos","events_url":"https://api.github.com/users/ianhays/events{/privacy}","received_events_url":"https://api.github.com/users/ianhays/received_events","type":"User","site_admin":false},"milestone":null,"comments":9,"created_at":"2015-11-13T21:36:31Z","updated_at":"2015-11-25T20:52:20Z","closed_at":null,"body":"Last summer I looked into new collections to consider adding to .NET. I ultimately decided on adding [the MultiValueDictionary](https://github.com/dotnet/corefxlab/pull/370), but a close contender was the bi-directional dictionary. Now that we have corefxlab and we're working in the open, I'd like to revisit the BiDictionary as a possible addition.\r\n\r\nIf I remember correctly, my basic implementation for a BiMap that I took to API review a year ago had two Dictionaries – one that maps from Key->Value and the other that maps Value->Key. Any time the BiMap is mutated, both internal dictionaries have to be updated. There was also a Property “Reverse” to get the Value->Key mapping such that you could do:\r\n\r\n```C#\r\nBiMap<int, string> map = new BiMap<int, string>();\r\nMap[1] = “cat”;\r\nBiMap<string, int> reverse = map.Reverse;\r\nAssert.Equal(1, reverse[“cat”]);\r\n```\r\n\r\nBoth “map” and “reverse” used the same internal store.\r\n\r\nSo moving forward we should look at the above as our “worst case” scenario. I think we can do something more clever.\r\n\r\nThe biggest design issue I'd like to get resolved is whether we should Implement `IDictionary<TKey, Value>` and `IDictionary<TValue, TKey>` or just the former.\r\n\r\n@ReedKimble\r\n"},"comment":{"url":"https://api.github.com/repos/dotnet/corefxlab/issues/comments/159728979","html_url":"https://github.com/dotnet/corefxlab/issues/446#issuecomment-159728979","issue_url":"https://api.github.com/repos/dotnet/corefxlab/issues/446","id":159728979,"user":{"login":"ianhays","id":2606879,"avatar_url":"https://avatars.githubusercontent.com/u/2606879?v=3","gravatar_id":"","url":"https://api.github.com/users/ianhays","html_url":"https://github.com/ianhays","followers_url":"https://api.github.com/users/ianhays/followers","following_url":"https://api.github.com/users/ianhays/following{/other_user}","gists_url":"https://api.github.com/users/ianhays/gists{/gist_id}","starred_url":"https://api.github.com/users/ianhays/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ianhays/subscriptions","organizations_url":"https://api.github.com/users/ianhays/orgs","repos_url":"https://api.github.com/users/ianhays/repos","events_url":"https://api.github.com/users/ianhays/events{/privacy}","received_events_url":"https://api.github.com/users/ianhays/received_events","type":"User","site_admin":false},"created_at":"2015-11-25T20:52:20Z","updated_at":"2015-11-25T20:52:20Z","body":">So I think we have a direction from a code-implementation point of view, now we just have to hammer down the actual API structure.\r\n\r\nAgreed. That's the fun part :)\r\n\r\n>I wondered about precedent as well and couldn't really think of any; that's why I'm not sure if those overloads should exist or not.\r\n\r\n>Though I suppose we could make it easier to use the wrappers by offering simple methods like MakeLeft(value As TLeft) As LeftValue so that consumers can just call instance.MakeLeft(x) when they need a wrapped value. Just talking about it, I think I like that idea better than AddRight/AddLeft/etc.\r\n\r\nSo to Add you would do \r\n```\r\nbiDictionary<T, T>;\r\nT leftThingToAdd, rightRightToAdd\r\nbiDictionary.Add(biDictionary.MakeLeft(leftThingToAdd), biDictionary.MakeRight(rightThingToAdd));\r\n```\r\n\r\nOr I suppose you could circumvent the necessity for the wrapper on one side by making the internal structure akin to a Dictionary<TLeft, TRightWrapper>, but that could get potentially very confusing. That would then look like:\r\n\r\n```\r\nbiDictionary<T, T>;\r\nT leftThingToAdd, rightRightToAdd\r\nbiDictionary.Add(leftThingToAdd, biDictionary.MakeRight(rightThingToAdd));\r\n```\r\n\r\nPersonally I don't like either of the above. I would rather just be able to do:\r\n```\r\nbiDictionary<T, T>;\r\nT leftThingToAdd, rightRightToAdd\r\nbiDictionary.AddByLeft(leftThingToAdd, rightThingToAdd);\r\n```\r\n\r\nor\r\n\r\n```\r\nbiDictionary<T, T>;\r\nT leftThingToAdd, rightRightToAdd\r\nbiDictionary.Add(leftThingToAdd, rightThingToAdd); //OR: biDictionary.Inverse.Add(rightThingToAdd, leftThingToAdd);\r\n```"}}