#algorithm #sorting #dart
#алгоритм #сортировка #dart
Вопрос:
Я пытаюсь выяснить, какой наилучший способ суммировать все те же количества элементов, в частности, данные формируются следующим образом:
data = [
{Item Name: Item 2, Quantity: 1},
{Item Name: Item 1, Quantity: 1},
{Item Name: Item 3, Quantity: 1},
{Item Name: Item 2, Quantity: 2},
{Item Name: Item 1, Quantity: 2},
{Item Name: Item 3, Quantity: 2},
];
и чего я пытаюсь достичь, так это:
totalList = [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}];
Я пытался использовать переменную TempData для удержания элемента и сравнения остальных, однако, похоже, что она сравнивает только этот первый элемент с остальной частью списка.
var tempData = {};
var totalList = [];
data.forEach((element) {
if (tempData.isEmpty) {
tempData = element;
totalList.add(tempData);
} else {
if (tempData['Item Name'] == element['Item Name']) {
tempData['Quantity'] = tempData['Quantity'] element['Quantity'];
totalList.add(tempData);
} else {
tempData = {
'Item Name': element['Item Name'],
'Quantity': element['Quantity']
};
totalList.add(tempData);
}
}
});
Вышеприведенное, похоже, не дало мне результата, который я искал…
Что я должен сделать вместо этого?
Заранее спасибо за вашу помощь.
Комментарии:
1. Какой результат это дает вам?
Ответ №1:
Ваша структура данных не очень хороша; метки 'Item Name'
и 'Quantity'
не очень полезны в самой структуре, поэтому я бы избавился от них и создал упрощенный Map<String, int>
, который напрямую сопоставляет имена с количествами. В идеале вы могли бы просто использовать упрощенную структуру с этого момента, но если вам действительно нужны явные метки, вы могли бы преобразовать обратно.
void main(List<String> args) async {
var data = [
{'Item Name': 'Item 2', 'Quantity': 1},
{'Item Name': 'Item 1', 'Quantity': 1},
{'Item Name': 'Item 3', 'Quantity': 1},
{'Item Name': 'Item 2', 'Quantity': 2},
{'Item Name': 'Item 1', 'Quantity': 2},
{'Item Name': 'Item 3', 'Quantity': 2},
];
// Sum everything into a simpler data structure.
var totalCounts = <String, int>{};
for (var map in data) {
var name = map['Item Name'] as String;
var quantity = map['Quantity'] as int;
totalCounts[name] = (totalCounts[name] ?? 0) quantity;
}
// Reformat back into the original structure.
var totalList = <Map<String, dynamic>>[
for (var entry in totalCounts.entries)
{'Item Name': entry.key, 'Quantity': entry.value},
];
// Optional: Sort.
totalList.sort((a, b) => a['Item Name'].compareTo(b['Item Name']));
print(totalList); // Prints: [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}]
}
В реальном коде я бы дополнительно добавил:
const nameLabel = 'Item Name';
const quantityLabel = 'Quantity';
и используйте их везде вместо строковых литералов, чтобы уменьшить возможности для внесения опечаток.
Ответ №2:
Я создал следующее решение, которое не такое красивое, но оно работает. Концепция заключается в создании Map<String, Map<String, Object>>
, который отслеживает элементы, которые мы уже посетили, используя «Название элемента» каждого элемента в качестве ключа.
void main() {
final data = [
{'Item Name': 'Item 2', 'Quantity': 1},
{'Item Name': 'Item 1', 'Quantity': 1},
{'Item Name': 'Item 3', 'Quantity': 1},
{'Item Name': 'Item 2', 'Quantity': 2},
{'Item Name': 'Item 1', 'Quantity': 2},
{'Item Name': 'Item 3', 'Quantity': 2},
];
final result = [
...data.fold(
<String, Map<String, Object>>{},
(Map<String, Map<String, Object>> sum, element) => sum
..update(
element['Item Name'] as String,
(value) => value
..update('Quantity',
(value) => (value as int) (element['Quantity'] as int)),
ifAbsent: () => Map.from(element))).values
];
result.sort(
(a, b) => (a['Item Name'] as String).compareTo(b['Item Name'] as String));
print(result); // [{Item Name: Item 1, Quantity: 3}, {Item Name: Item 2, Quantity: 3}, {Item Name: Item 3, Quantity: 3}]
}