какую коллекцию c# использовать вместо списка?

Я хочу хранить такие данные, как

{
 {"apple",15   }
 {"pear",12.5  }
 {"", 10       }
 {"", 0.45     }
}

данные будут отображаться на гистограмме (строка будет легендой, а double-значением) Порядок вставки важен. Перфы не имеют значения. строки могут быть дублированы или пусты. (значения также могут быть продублированы)

мне нужно получить минимальные и максимальные значения (легко, если это возможно), чтобы установить масштаб.

Я использую

List<KeyValuePair<string, double>> data = new List<KeyValuePair<string, double>>();
data.Add(new KeyValuePair<string,double>("",i));

довольно скучно и нечитабельно. Есть ли более чистый способ сделать это ?

StringDoubleCollection data = new StringDoubleCollection();
data.add("apple",15);
data.add("",10);

double max = data.values.Max(); 
double min = data.values.Min();

если не как получить максимальное значение List<KeyValuePair<string, double>> без проблем

NameValueCollection выглядит красиво, но его <string,string> мне нужно <string,double>

спасибо

6 ответов


чтобы определить, какую структуру данных вы действительно хотите, давайте посмотрим на ваши шаблоны использования.

  • порядок вставки имеет значение.
  • вы не получаете доступ к своим элементам по ключу.
  • вы хотите min и max.

куча предлагает min или Макс, но не сохраняет порядок. Словарь на основе хэша также не сохраняет порядок. Список на самом деле является хорошим выбором для вашей структуры данных. Он доступен и предлагает отличные поддержка.

вы можете улучшить свой код, определив классы как для структуры данных, так и для данных панели. И вы можете добавить функциональность min/max в коллекцию. Примечание: Я не использовал функции Linq Min/Max, потому что они возвращают минимум стоимостью, не менее элемент.

public class BarGraphData {
    public string Legend { get; set; }
    public double Value { get; set; }
}

public class BarGraphDataCollection : List<BarGraphData> {
    // add necessary constructors, if any

    public BarGraphData Min() {
        BarGraphData min = null;
        // finds the minmum item
        // prefers the item with the lowest index
        foreach (BarGraphData item in this) {
            if ( min == null )
                min = item;
            else if ( item.Value < min.Value )
                min = item;
        }
        if ( min == null )
            throw new InvalidOperationException("The list is empty.");
        return min;
    }

    public BarGraphData Max() {
        // similar implementation as Min
    }
}

вы можете создать следующий класс:

class X
{
     public string Name { get; set; }
     public double Value { get; set; }

     // name is an optional parameter (this means it can be used only in C# 4)
     public X(double value, string name = "")
     {
         this.Name = name;
         this.Value = value;
     }

     // whatever
}

а затем получить максимальное и минимальное значения с помощью LINQ с селектором:

var data = new List<X>();
data.Add(new X(35.0, "Apple"))
data.Add(new X(50.0));

double max = data.Max(a => a.Value);
double min = data.Min(a => a.Value);

EDIT: если код выше по-прежнему кажется вам нечитаемым, попробуйте улучшить его, используя оператор для случаев, в которых вы хотите иметь только значение.

// Inside X class...
public static implicit operator X(double d)
{
    return new X(d);
}

// Somewhere else...
data.Add(50.0);

вы смотрели Поиск?

единственная проблема заключается в том, что она неизменна, поэтому вам нужно иметь возможность создавать свою коллекцию за один раз.

Как отмечает Энтони Пеграм, это немного больно, чтобы создать его. Это зависит от того, откуда поступают данные. Взгляните на метода tolookup метод.


Если это стоит того для удобства использования (т. е. вы используете неудобные коллекции List<KeyValuePair<string, double>> везде, это может просто стоить того, чтобы реализовать StringDoubleCollection. Было бы не так сложно обернуть базовую коллекцию более дружелюбным синтаксисом, который вы описали в своем примере.

и, как предлагают другие комментарии / ответы, структура, похоже, не обеспечивает более простое решение, которое соответствует всем вашим требованиям...

Что касается "максимального значения", я полагаю, вы имеете в виду пара ключ-значение с наибольшим значением. Его можно получить следующим образом:

var max = list.Select(kvp => kvp.Value).Max();

просто определите свой собственный класс модели для хранения данных, а не в зависимости от KeyValuePair, и все станет чище:

using System;
using System.Collections.Generic;

public class Fruit
{
    public string Name {get; set;}
    public double Price {get; set;}
}

public class Program
{
    public static void Main()
    {
        List<Fruit> _myFruit = new List<Fruit>();

        _myFruit.Add(new Fruit{Name="apple", Price=15   });
        _myFruit.Add(new Fruit{Name="pear", Price=12.5  });
        _myFruit.Add(new Fruit{Name="",  Price=10       });
        _myFruit.Add(new Fruit{Name="",  Price=0.45     });

        // etc...
    }
}

Как насчет реализации StringDoubleCollection для работы так, как вы хотите...

public class StringDoubleCollection
{
    private List<KeyValuePair<string, double>> myValues;
    public List<double> values
    {
        get { return myValues.Select(keyValuePair => keyValuePair.Value).ToList(); }
    }

    public void add(string key, double value)
    {
        myValues.Add(new KeyValuePair<string,double>(key,value));
    }
}