如何按List(Of Object)的键对字典进行分组?

时间:2013-10-03 08:19:19

标签: .net linq list dictionary

我有Dictionary(Of List(Of Object), Integer),需要按键分组我的词典。

例如:

Dictionary (0) = Key: {List(12, "SomeString", 3)} Value: 54

Dictionary (1) = Key: {List(8, "SomeAnotherString", 3)} Value: 6

Dictionary (2) = Key: {List(12, "SomeString", 3)} Value: 15

我如何才能看到Dictionary

Dictionary (0) = Key: {List(12, "SomeString", 3)} Value: 54, 15

Dictionary (1) = Key: {List(8, "SomeAnotherString", 3)} Value: 6

2 个答案:

答案 0 :(得分:0)

我在C#中提供了一个解决方案,但将其转换为VB.NET对您来说应该不是问题。

此外,我假设List(对象)中存在的对象数始终为3,并且类型为int,string,int。

以下是我解决您问题的方法。

  1. 创建一个新类,说“MyList”,它继承自List(对象)
  2. 覆盖“MyList”类中​​的Equals方法,并在该方法中通过检查每个元素检查传递的列表是否与当前列表相同
  3. 将原始字典创建为key =“MyList”,value = int
  4. 创建一个新词典key =“MyList”,value = List(of int)
  5. 创建一个方法,该方法将调用overriden equals方法并在返回false时添加新的键/值,如果返回true则将值添加到该键
  6. 以下是整个代码

        Dictionary<MyList, List<int>> newOtherDict;
    
        private void button1_Click(object sender, EventArgs e)
        {
            //Dummy data for testing
            Dictionary<MyList, int> myDict = new Dictionary<MyList, int>();
            myDict.Add(new MyList() {1, "SomeString", 3 }, 1);
            myDict.Add(new MyList() { 1, "SomeOtherString", 3 }, 12);
            myDict.Add(new MyList() { 1, "SomeString", 3 }, 123);
    
            //This dictionary will contain the consolidated values
            newOtherDict = new Dictionary<MyList, List<int>>();
    
            for (int i = 0; i < myDict.Count; i++)
            {
                AddOrAppendToNewDict(myDict.ElementAt(i));
            }
        }
    
        private void AddOrAppendToNewDict(KeyValuePair<MyList, int> keyValue)
        {
            var foundPair = newOtherDict.Where(x => x.Key.Equals(keyValue.Key));
    
            if (foundPair.Count() == 0)
            {
                newOtherDict.Add(keyValue.Key, new List<int>() { keyValue.Value });
            }
            else
            {
                foundPair.First().Value.Add(keyValue.Value);
            }
        }
    
        class MyList : List<object>
        {
            public override bool Equals(object obj)
            {
                List<object> toCompareClass = obj as List<object>;
    
                if (Convert.ToInt32(this[0]) == Convert.ToInt32(toCompareClass[0]) &&
                    Convert.ToInt32(this[2]) == Convert.ToInt32(toCompareClass[2]) &&
                    this[1].ToString() == toCompareClass[1].ToString())
                    return true;
    
                return false;
            }
        }
    

    我希望这能解决你的问题。

    此致

    萨马

答案 1 :(得分:0)

我认为您不了解字典是如何工作的。 字典的值由其唯一键访问。在内部,使用密钥生成的哈希码查找它们。要正常工作,哈希码需要一些属性:

  • 两个比较相等的对象必须具有相同的哈希码。

  • 如果可变对象产生依赖于其可变状态的哈希码,则不应将其用作字典中的键。原因很简单:如果将这样的对象放入哈希表中并进行变异,则无法再次找到它。

哈希码由GetHashCode函数生成,可以被任何类型覆盖。 您使用List(Of Object)作为键值。 List(Of Object)不会覆盖GetHashCode。它使用Object类型的默认实现。虽然这种实现符合规定的要求,但绝对不是您想要的。

我注意到您尝试用作键的列表始终具有相同的结构:整数,字符串和另一个整数。 List(Of Object)不是键的好选择。但也许你可以创建一个可以用作密钥的类型:

Public Class MyKey
    Private ReadOnly _firstValue As Integer
    Private ReadOnly _secondValue As String
    Private ReadOnly _thirdValue As Integer

    Public Sub New(firstValue As Integer, secondValue As String, thirdValue As Integer)
        _firstValue = firstValue
        _secondValue = secondValue
        _thirdValue = thirdValue
    End Sub

    Public ReadOnly Property FirstValue As Integer
        Get
            Return _firstValue
        End Get
    End Property

    Public ReadOnly Property SecondValue As String
        Get
            Return _secondValue
        End Get
    End Property

    Public ReadOnly Property ThirdValue As Integer
        Get
            Return _thirdValue
        End Get
    End Property

    Public Overloads Function GetHashCode() As Integer
        Dim hashCode As Integer = 31
        hashCode = hashCode + 17 * _firstValue
        hashCode = hashCode + 17 * _secondValue.GetHashCode()
        hashCode = hashCode + 17 * _thirdValue

        Return hashCode
    End Function

    Public Overloads Function Equals(obj As Object) As Boolean
        If TypeOf obj Is MyKey Then
            Dim other As MyKey = CType(obj, MyKey)
            Return _firstValue = other._firstValue And
                   _secondValue = other._secondValue And
                   _thirdValue = other._thirdValue
        Else
            Return False
        End If
    End Function
End Class

此类型可用于字典键。它会生成一个正确的哈希码并覆盖Equals来比较内容而不是引用。另外,确保哈希码永远不会改变是不可变的。

字典需要唯一键。由于您的键不唯一,因此值必须是List(Of Integer)类型。添加值需要一些额外的工作。首先,您必须检查字典中是否已存在密钥。如果没有创建新条目:

Dim dictionary As New Dictionary(Of MyKey, List(Of Integer))
Add(dictionary, New MyKey(12, "SomeString", 3), 54)
Add(dictionary, New MyKey(8, "SomeAnotherString", 3), 6)
Add(dictionary, New MyKey(12, "SomeString", 3), 15)

Public Sub Add(dictionary As Dictionary(Of MyKey, List(Of Integer)), key As MyKey, value As Integer)
    Dim list As List(Of Integer) = Nothing
    If Not dictionary.TryGetValue(key, list) Then
        list = New List(Of Integer)()
        dictionary.Add(key, list)
    End If

    list.Add(value)
End Sub