Reputation: 5236
My requirement is as follows. I need a Dictionary<string,List<object>>
and each object
in one List
of one <Key,Value>
Pair must have a reference to an object
in the previous
<Key,Value>
pair's List and a reference to an object
in the next
<Key,Value>
pair's List. So essentially, I have a horizontal list for each Value in the dictionary and vertical bi-directional lists associating elements of the horizontal lists, if that makes any sense. Can someone throw some light on how I can achieve this datastructure?
Upvotes: 2
Views: 3119
Reputation: 2174
So it sounds like you want a bunch of linkedlists, where each linked list contains a user's choices made in chronological order. Furthermore, you want to be able to access all user choices for a specific year. So the way I've done it below first builds a list of linkedlistnode objects (NOT a linkedlist), then uses linq to build a dictionary of these nodes keyed by year.
I've made an assumption that only one change per user is recorder per year.
var TheActualChoiceIsIrrelevantForThisExample = new Choice();
var Ditto = new Choice();
var userChoices = new List<UserChoice>
{
new UserChoice("2000", 1, TheActualChoiceIsIrrelevantForThisExample ),
new UserChoice("2000", 2, Ditto ),
new UserChoice("2000", 3, Ditto ),
new UserChoice("1999", 1, Ditto ),
new UserChoice("1999", 2, Ditto ),
new UserChoice("1999", 3, Ditto ),
new UserChoice("2001", 1, Ditto ),
new UserChoice("2001", 2, Ditto ),
new UserChoice("2001", 3, Ditto ),
};
var userChoicesGroupedById =
from userChoice in userChoices
group userChoice by userChoice.UserId;
/*using List of LinkedListNode allows linq queries to access the nodes' previous and next properties.
* if a linkedlist was used, then these properties would not be accessible (because we would be querying UserChoice objects, not LinkedListNodes)
*/
var linkedUserChoices = new List<LinkedListNode<UserChoice>>();
foreach (var grp in userChoicesGroupedById)
{
var userChoicesSortedByYear =new LinkedList<UserChoice>( grp.OrderBy(userChoice=>userChoice.Year));
var currentNode = userChoicesSortedByYear.First;
while (currentNode != null)
{
linkedUserChoices.Add(currentNode);
currentNode = currentNode.Next;
}
}
var userChoicesGroupedByYear =
(from userChoiceNode in linkedUserChoices
group userChoiceNode by userChoiceNode.Value.Year).ToList();
var dictionary = userChoicesGroupedByYear.ToDictionary(group => group.Key, group => group.ToList());
here are the class definitions for the objects I've used:
class UserChoice
{
public string Year { get; set; }
public Choice Choice { get; set; }
public int UserId { get; set; }
public UserChoice(string year, int userId, Choice choice )
{
Year = year;
Choice = choice;
UserId = userId;
}
}
class Choice
{
}
Once the final dictionary is built it can be used like:
dictionary["2000"]
.Single(node=>node.Value.UserId == 42)
.Next //forward one node - i.e. the next year that the user made a choice. Not neccessarily the next calendar year.
.Previous.Previous.Previous //back three nodes
//etc
Upvotes: 1
Reputation: 14518
Are you looking for a Linked List?
I've used it for linking the data of a wizard together so we know exactly what data is used on each page.
Maybe you can tell us what you want to use it for?
Update:
Below is a little example of how you can use Linq grouping to get what you're looking for. Paste it in a console app to see the results.
class Program
{
static void Main(string[] args)
{
User user1 = new User { UserName = "Tom" };
User user2 = new User { UserName = "Pete" };
List<UserChoice> userChoices = new List<UserChoice>
{
new UserChoice { User = user1, ChosenValue = "chosenValue1", Year = 1994 },
new UserChoice { User = user1, ChosenValue = "chosenValue3", Year = 1995 },
new UserChoice { User = user1, ChosenValue = "chosenValue1", Year = 1996 },
new UserChoice { User = user1, ChosenValue = "chosenValue2", Year = 1997 },
new UserChoice { User = user1, ChosenValue = "chosenValue2", Year = 1998 },
new UserChoice { User = user1, ChosenValue = "chosenValue1", Year = 1999 },
new UserChoice { User = user1, ChosenValue = "chosenValue2", Year = 2000 },
new UserChoice { User = user2, ChosenValue = "chosenValue3", Year = 1994 },
new UserChoice { User = user2, ChosenValue = "chosenValue1", Year = 1995 },
new UserChoice { User = user2, ChosenValue = "chosenValue2", Year = 1996 },
new UserChoice { User = user2, ChosenValue = "chosenValue3", Year = 1997 },
new UserChoice { User = user2, ChosenValue = "chosenValue1", Year = 1998 },
new UserChoice { User = user2, ChosenValue = "chosenValue2", Year = 1999 },
new UserChoice { User = user2, ChosenValue = "chosenValue1", Year = 2000 }
};
var choicesByYear = (from uc in userChoices
group uc by uc.Year into g
select new { Year = g.Key, UserChoicesByYear = g });
foreach (var item in choicesByYear)
{
Console.WriteLine("Choices for year: " + item.Year);
foreach (var userChoice in item.UserChoicesByYear)
{
Console.WriteLine(userChoice.User.UserName + " chose " + userChoice.ChosenValue.ToString());
}
}
Console.ReadKey();
}
}
public class UserChoice {
public User User { get; set; }
public int Year { get; set; }
public object ChosenValue { get; set; }
}
public class User {
public string UserName { get; set; }
}
Upvotes: 1
Reputation: 19349
Do you intend that, say, the first object in one list will reference the first object in next list and the first object in the previous list? Or can they reference arbitrary objects?
If they are all lined up, you may want to consider using a table structure. The only one of know of right now is the System.Data.DataTable. It's actually used for building relational databases, but it seems like it could be used here.
You could also defined your own data structure which simply wraps a List of KeyValuePair. This way you can maintain ordering as you wish, and can access everything by index, thereby simulating the row/columns structure of a table.
Upvotes: 0