0

我已经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
4

2 回答 2

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
于 2013-10-03T14:45:45.967 回答
0

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

此外,我假设 List(of object) 中存在的对象数始终为 3,并且按 int、string、int 类型的顺序排列。

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

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

以下是整个代码

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

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

问候,

萨马尔

于 2013-10-03T12:16:04.263 回答