С# эквивалент карты С++‹string,double›

Я хочу сохранить некоторые итоги для разных учетных записей. В С++ я бы использовал STL следующим образом:

map<string,double> accounts;

// Add some amounts to some accounts.
accounts["Fred"] += 4.56;
accounts["George"] += 1.00;
accounts["Fred"] += 1.00;

cout << "Fred owes me $" << accounts['Fred'] << endl;

Теперь, как бы я сделал то же самое на C#?


person Adam Pierce    schedule 21.10.2009    source источник


Ответы (7)


Грубо:-

var accounts = new Dictionary<string, double>();

// Initialise to zero...

accounts["Fred"] = 0;
accounts["George"] = 0;
accounts["Fred"] = 0;

// Add cash.
accounts["Fred"] += 4.56;
accounts["George"] += 1.00;
accounts["Fred"] += 1.00;

Console.WriteLine("Fred owes me ${0}", accounts["Fred"]);
person ljs    schedule 21.10.2009
comment
Это очень близко к тому, что мне нужно, единственный недостаток - я не знаю, какие будут имена аккаунтов раньше времени. - person Adam Pierce; 21.10.2009
comment
Вам не нужно знать их заранее. В примерах для краткости используются константные строки, но вы можете использовать строковые объекты. - person XXXXX; 21.10.2009
comment
Возможно, мне следует уточнить этот комментарий, сказав, что я не знаю имен или сколько имен у меня будет. В этом ответе, если я добавлю учетные записи [Рон] += 2,50;, это вызовет исключение. На самом деле, я буду бросать в него файл XML с множеством имен и номеров. - person Adam Pierce; 21.10.2009
comment
На самом деле нет, если вы используете индекс и пытаетесь установить несуществующий ключ, он фактически создаст для вас объект с указанным ключом. Исключение будет выдано только при операции получения. Посмотрите здесь на замечания: msdn.microsoft.com/en-us/library/9tee9ht2 .aspx - person Alastair Pitts; 21.10.2009
comment
Erebus прав: вы можете произвольно добавлять вещи в словарь, не зная во время компиляции, что или сколько элементов будет в словаре. - person XXXXX; 21.10.2009
comment
Почему людям так нравится var? - person Alex; 09.04.2013
comment
@Alex: потому что var намного короче, чем IParallelEnumerable‹Record‹string,XmlSerializer›› :) - person DarkWanderer; 06.12.2013
comment
Словари в С# не эквивалентны stl::map, просто чтобы вы знали - словари С# представляют собой хэш-таблицы, тогда как stl::map - красно-черные деревья, лежащие в их основе алгоритмы совершенно разные. - person Kevin Depue; 24.04.2014
comment
Обратите внимание, что accounts["Fred"] = 0;в этом примере эквивалентно accounts.Add("Fred", 0); (см. dotnetfiddle.net/q3UteL для обоих вариантов). Также: *Когда вы используете Dictionary.Add( Key, Value ) для добавления нового KeyValuePair, будет выбран ArgumentException, если Key уже существует в словаре. *Используя индексатор (Dictionary[ Key ]), вы получаете неявное поведение добавить или обновить, поскольку Key будет автоматически добавлено, если оно еще не содержится в словаре, в противном случае соответствующее значение будет просто обновлено. * Рассмотрите возможность использования десятичной дроби для валюты. - person Marcus Mangelsdorf; 07.10.2015

Хотя System.Collections.Generic.Dictionary соответствует тегу "hashmap" и будет хорошо работать в вашем примере, он не является точным эквивалентом C++ std::map - std::map является упорядоченной коллекцией.

Если важен порядок, используйте SortedDictionary.

person user200783    schedule 21.10.2009

Вам нужен класс Dictionary.

person Daniel Pryden    schedule 21.10.2009

Словарь является наиболее распространенным, но вы можете использовать и другие типы коллекций, например. System.Collections.Generic.SynchronizedKeyedCollection, System.Collections.Hashtable или любая коллекция KeyValuePair

person Jim Schubert    schedule 21.10.2009

Этот код - все, что вам нужно:

   static void Main(string[] args) {
        String xml = @"
            <transactions>
                <transaction name=""Fred"" amount=""5,20"" />
                <transaction name=""John"" amount=""10,00"" />
                <transaction name=""Fred"" amount=""3,00"" />
            </transactions>";

        XDocument xmlDocument = XDocument.Parse(xml);

        var query = from x in xmlDocument.Descendants("transaction")
                    group x by x.Attribute("name").Value into g
                    select new { Name = g.Key, Amount = g.Sum(t => Decimal.Parse(t.Attribute("amount").Value)) };

        foreach (var item in query) {
            Console.WriteLine("Name: {0}; Amount: {1:C};", item.Name, item.Amount);
        }
    }

А содержание такое:

Имя: Фред; Сумма: 8,20 реалов;
Имя: Джон; Сумма: 10 реалов;

Именно так это делается в C# — декларативно!

Надеюсь, это поможет,

Рикардо Ласерда Каштелу Бранко

person Community    schedule 21.10.2009
comment
Что ж, я уже сделал это со словарем, но XML очень прост, просто список таких тегов: ‹имя транзакции=сумма Фреда=5,20 /› - person Adam Pierce; 21.10.2009


Ближайшим эквивалентом C++ std::map<> (внутреннее дерево) является C# OrderedDictionary<> (внутреннее дерево), тогда как в C# OrderedDictionary<> отсутствуют некоторые очень важные методы из C++ std::map<>, а именно: std::map::find, std::map::lower_bound, std::map::upper_bound, std::map::equal_range и std::map iterators, которые в основном основу для предыдущих 4 методов.

Почему эти 4 метода важны? Потому что это дает нам возможность определить «местонахождение» данного ключа, в дополнение к возможности только проверить, существует ли ключ, или SortedDictionary гарантированно будет упорядочен.

Что такое «местонахождение» ключа в std::map? Ключ не обязательно должен существовать в коллекции, мы хотим знать местоположение, в котором может находиться ключ, обычно между двумя итераторами, указывающими на два соседних существующих ключа соответственно в коллекции, поэтому мы можем работать с диапазоном ключ имеет сложность O(logN). Без таких 4 методов (с итераторами) необходимо выполнять O(N) итераций по коллекции каждый раз, когда диапазон запрашивается по ключу.

person Dejavu    schedule 20.03.2017