在嵌套地图内的列表中添加和删除值会影响所有嵌套地图
Adding and removing values in a list inside a nested Map affects all nested Maps
几天来我一直在为这个问题苦苦挣扎,我通常不是在这里提问的人,但这次我真的很好奇我将如何解决这个问题..
事实是,我有一个地图,它是一个 "unique identifier" 用于假设的赛马优惠券 (<int,
) 和一个代表(键:用于列)和(值:用于行)对于假设的种族和每场比赛中的马匹,所以这个变量看起来像这样:(Map<int, Map<int, List<int>>> couponData = new Map();
)。
打印这样的结果例如:
{1: {0: [1,6], 1: [], 2: [2,6], 3: [], 4: [3,6,7,8], 5: [], 6: []}}
或者更直白地说:
{Coupon1: {Race1: [Horse1,Horse6], Race2: [], Race3: [Horse2,Horse6], Race4: [], Race5: [Horse3,Horse6,Horse7,Horse8], Race6: [], Race7: []}}
现在一切正常。然而,我的问题是,当我在每场比赛(或名单)中添加新马或删除它们时。
如果我有多张优惠券并且只想更换我的另一张优惠券中的一匹马,它会影响所有优惠券,而不仅仅是我当前选择的那匹马。所以代码看起来像这样:
int activeCoupon = 1;
if (!couponData[activeCoupon][raceNumber].contains(horseNumber + 1)) {
couponData[activeCoupon][raceNumber].add(horseNumber + 1);
} else {
couponData[activeCoupon][raceNumber].remove(horseNumber + 1);
}
在我的第一张优惠券(共 2 张)的第一场比赛中选择马 1 和马 2 并在控制台中打印优惠券数据现在如下所示:
{1: {0: [1, 2], 1: [], 2: [], 3: [], 4: [], 5: [], 6: []}, 2: {0: [1, 2], 1: [], 2: [], 3: [], 4: [], 5: [], 6: []}}
这意味着它已将马 1 和马 2 添加到两张优惠券中,即使我指定我想在第一个优惠券中添加或删除,因此 (activeCoupon = 1
)。我在嵌套地图中添加和删除列表有什么问题吗?
我尝试了很多不同的方法,例如进入 .forEach 并手动添加和删除与各个种族和马匹相关的值,但结果相同..
关于我将如何以不同方式执行此操作的任何线索?
干杯
你实际上没有指定问题中的重要部分,但通过了解 Map
s 和 List
s 的工作原理,我可以知道问题出在哪里:你对它们的初始化不正确。
事实是,Map
和 List
指向内存中的位置,当您执行以下操作时:
final map1 = {};
final map2 = map1;
您现在将拥有两个指向内存中相同位置的地图,因此编辑 map1
也会影响 map2
。
话虽如此,我可以给你一些重要的提示:
构建您的(可能不是理想的优惠券赛马数据结构)时,请确保您将每个条目分配给具有 实际不同 值的地图,也就是说,不要创建一次你的 6 场比赛然后 "copy" 它们到你的其他优惠券,而是为每个优惠券创建它。
您可以使用 List.of
and Map.of
来 复制 地图或列表,但请注意,这 不是 deep复制,这意味着复制一个Map<int, List<int>>
将不会为你复制列表,这意味着它们仍然是一样。
在你的问题中包括你所做的与你的问题相关的所有事情——这里你没有包括唯一相关的部分:创建你的 Map<int, Map<int, List<int>>
.
阅读 this Wikipedia article 以了解有关复制的更多信息。
浅拷贝问题
我只是想快速说明这一点,以确保您明白这一点:
final map1 = {
1: [1, 2],
2: [3, 4],
};
final map2 = Map.of(map1);
你可能会想:"Oh, I followed the advice to copy my data using Map.of
. Now I should be fine."然而,这是一个谬论,因为你在地图中仍然有你的列表,没有复制,所以会出现以下情况:
map1[1].remove(2);
print(map1[1]); // [1]
print(map2[1]); // [1]
如您所见,两张地图中的列表都已更改。如果你也想只复制列表的内容,你需要这样做:
final map2 = {};
for (final entry in map1.entries) {
map2[entry.key] = List.of(entry.value);
}
这是一个深拷贝,完整代码如下所示:
void main() {
final map1 = {
1: [1, 2],
2: [3, 4],
};
final map2 = {};
for (final entry in map1.entries) {
map2[entry.key] = List.of(entry.value);
}
map1[1].remove(2);
print(map1[1]); // [1]
print(map2[1]); // [1, 2]
}
感谢@creativecreatorormaybenot解决了它。
很难解释我在上下文之外创建的所有变量,但这是我排除的导致问题的代码行:
final oldCouponData = couponData;
couponData = <int, Map>{activeCoupon: selected};
oldCouponData.addAll(couponData);
couponData = oldCouponData;
此上下文中的 selected
变量是当前优惠券的副本,它作为该优惠券的副本与选择优惠券的标识符(整数)一起放入 couponData。
这是我保留旧数据并向其添加新数据的方式。但是在阅读了地图和列表如何工作的解释后,我现在知道直接复制或使列表彼此相等会把事情搞砸,应该以不同的方式完成,正如 creativecreatorormaybenot 指出的那样。
几天来我一直在为这个问题苦苦挣扎,我通常不是在这里提问的人,但这次我真的很好奇我将如何解决这个问题..
事实是,我有一个地图,它是一个 "unique identifier" 用于假设的赛马优惠券 (<int,
) 和一个代表(键:用于列)和(值:用于行)对于假设的种族和每场比赛中的马匹,所以这个变量看起来像这样:(Map<int, Map<int, List<int>>> couponData = new Map();
)。
打印这样的结果例如:
{1: {0: [1,6], 1: [], 2: [2,6], 3: [], 4: [3,6,7,8], 5: [], 6: []}}
或者更直白地说:
{Coupon1: {Race1: [Horse1,Horse6], Race2: [], Race3: [Horse2,Horse6], Race4: [], Race5: [Horse3,Horse6,Horse7,Horse8], Race6: [], Race7: []}}
现在一切正常。然而,我的问题是,当我在每场比赛(或名单)中添加新马或删除它们时。
如果我有多张优惠券并且只想更换我的另一张优惠券中的一匹马,它会影响所有优惠券,而不仅仅是我当前选择的那匹马。所以代码看起来像这样:
int activeCoupon = 1;
if (!couponData[activeCoupon][raceNumber].contains(horseNumber + 1)) {
couponData[activeCoupon][raceNumber].add(horseNumber + 1);
} else {
couponData[activeCoupon][raceNumber].remove(horseNumber + 1);
}
在我的第一张优惠券(共 2 张)的第一场比赛中选择马 1 和马 2 并在控制台中打印优惠券数据现在如下所示:
{1: {0: [1, 2], 1: [], 2: [], 3: [], 4: [], 5: [], 6: []}, 2: {0: [1, 2], 1: [], 2: [], 3: [], 4: [], 5: [], 6: []}}
这意味着它已将马 1 和马 2 添加到两张优惠券中,即使我指定我想在第一个优惠券中添加或删除,因此 (activeCoupon = 1
)。我在嵌套地图中添加和删除列表有什么问题吗?
我尝试了很多不同的方法,例如进入 .forEach 并手动添加和删除与各个种族和马匹相关的值,但结果相同..
关于我将如何以不同方式执行此操作的任何线索? 干杯
你实际上没有指定问题中的重要部分,但通过了解 Map
s 和 List
s 的工作原理,我可以知道问题出在哪里:你对它们的初始化不正确。
事实是,Map
和 List
指向内存中的位置,当您执行以下操作时:
final map1 = {};
final map2 = map1;
您现在将拥有两个指向内存中相同位置的地图,因此编辑 map1
也会影响 map2
。
话虽如此,我可以给你一些重要的提示:
构建您的(可能不是理想的优惠券赛马数据结构)时,请确保您将每个条目分配给具有 实际不同 值的地图,也就是说,不要创建一次你的 6 场比赛然后 "copy" 它们到你的其他优惠券,而是为每个优惠券创建它。
您可以使用
List.of
andMap.of
来 复制 地图或列表,但请注意,这 不是 deep复制,这意味着复制一个Map<int, List<int>>
将不会为你复制列表,这意味着它们仍然是一样。在你的问题中包括你所做的与你的问题相关的所有事情——这里你没有包括唯一相关的部分:创建你的
Map<int, Map<int, List<int>>
.
阅读 this Wikipedia article 以了解有关复制的更多信息。
浅拷贝问题
我只是想快速说明这一点,以确保您明白这一点:
final map1 = {
1: [1, 2],
2: [3, 4],
};
final map2 = Map.of(map1);
你可能会想:"Oh, I followed the advice to copy my data using Map.of
. Now I should be fine."然而,这是一个谬论,因为你在地图中仍然有你的列表,没有复制,所以会出现以下情况:
map1[1].remove(2);
print(map1[1]); // [1]
print(map2[1]); // [1]
如您所见,两张地图中的列表都已更改。如果你也想只复制列表的内容,你需要这样做:
final map2 = {};
for (final entry in map1.entries) {
map2[entry.key] = List.of(entry.value);
}
这是一个深拷贝,完整代码如下所示:
void main() {
final map1 = {
1: [1, 2],
2: [3, 4],
};
final map2 = {};
for (final entry in map1.entries) {
map2[entry.key] = List.of(entry.value);
}
map1[1].remove(2);
print(map1[1]); // [1]
print(map2[1]); // [1, 2]
}
感谢@creativecreatorormaybenot解决了它。
很难解释我在上下文之外创建的所有变量,但这是我排除的导致问题的代码行:
final oldCouponData = couponData;
couponData = <int, Map>{activeCoupon: selected};
oldCouponData.addAll(couponData);
couponData = oldCouponData;
此上下文中的 selected
变量是当前优惠券的副本,它作为该优惠券的副本与选择优惠券的标识符(整数)一起放入 couponData。
这是我保留旧数据并向其添加新数据的方式。但是在阅读了地图和列表如何工作的解释后,我现在知道直接复制或使列表彼此相等会把事情搞砸,应该以不同的方式完成,正如 creativecreatorormaybenot 指出的那样。