У меня есть набор элементов / ключей, которые я читаю из двух разных файлов конфигурации. Таким образом, ключи могут быть одинаковыми, но с разными значениями, связанными с каждым из них.
Я хочу перечислить их в отсортированном порядке. Что я могу сделать ? Я пробовал с классом SortedList
, но он не позволяет дублировать ключи.
Как я могу это сделать?
Например, допустим, у меня есть 3 элемента с ключами 1,2,3. Затем я получаю еще один элемент, имеющий ключ 2 (но другое значение). Затем я хочу, чтобы новый ключ вставлялся после существующего ключа 2, но до 3. Если я хочу найти элемент с ключом 2, затем он должен идти после последнего добавленного ключа 2.
Обратите внимание, чем я пользуюсь .NET 2.0
Я предпочитаю использовать LINQ для этого типа вещей:
using System.Linq;
...
var mySortedList = myList.Orderby(l => l.Key)
.ThenBy(l => l.Value);
foreach (var sortedItem in mySortedList) {
//You'd see each item in the order you specified in the loop here.
}
Примечание: для этого вы должны использовать .NET 3.5 или более позднюю версию.
вам нужна функция сортировки с настраиваемым IComparer . Теперь у вас есть icomparer по умолчанию, когда вы используете сортировку. это проверит значение поля.
Когда вы создаете собственный IComparer (вы делаете это в своем классе, реализуя интерфейс Icomparable ). что он делает: ваш объект проверяет себя на все остальные объекты в сортируемом вами списке.
это делается функцией. (не волнуйтесь, VS реализует это при обращении к вашему интерфейсу
public class ThisObjectCLass : IComparable{
public int CompareTo(object obj) {
ThisObjectCLass something = obj as ThisObjectCLass ;
if (something!= null)
if(this.key.CompareTo(object.key) == 0){
//then:
if .....
}
else if(this.value "is more important then(use some logic here)" something.value){
return 1
}
else return -1
else
throw new ArgumentException("I am a dumb little rabid, trying to compare different base classes");
}
}
, прочтите ссылки выше, чтобы получить более подробную информацию.
Я знаю, что у меня были некоторые проблемы с пониманием этого вначале, поэтому для любой дополнительной помощи добавьте комментарий и Разработаю
.NET не имеет большой поддержки для стабильных сортировок (это означает, что эквивалентные элементы сохраняют свой относительный порядок при сортировке). Однако вы можете написать свою собственную стабильно-отсортированную вставку, используя List.BinarySearch
и пользовательский IComparer
(который возвращает -1, если ключ меньше или равно цели и +1, если больше).
Обратите внимание, что List.Sort
не является стабильной сортировкой, поэтому вам придется либо написать свою собственную стабильную процедуру быстрой сортировки, либо просто использовать сортировку вставкой для первоначального заполнения коллекции.
Если вас не волнует последовательность элементов с одинаковыми ключами, добавьте все в список, а затем отсортируйте его по ключу:
static void Main(string[] args)
{
List<KeyValuePair<int, MyClass>> sortedList =
new List<KeyValuePair<int, MyClass>>() {
new KeyValuePair<int, MyClass>(4, new MyClass("four")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven")),
new KeyValuePair<int, MyClass>(5, new MyClass("five")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-b")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven-b"))
};
sortedList.Sort(Compare);
}
static int Compare(KeyValuePair<int, MyClass> a, KeyValuePair<int, MyClass> b)
{
return a.Key.CompareTo(b.Key);
}
Если вы действительно хотите, чтобы элементы вставлялись позже чтобы быть после вставленных ранее, отсортируйте их по мере вставки:
class Sorter : IComparer<KeyValuePair<int, MyClass>>
{
static void Main(string[] args)
{
List<KeyValuePair<int, MyClass>> sortedList = new List<KeyValuePair<int, MyClass>>();
Sorter sorter = new Sorter();
foreach (KeyValuePair<int, MyClass> kv in new KeyValuePair<int, MyClass>[] {
new KeyValuePair<int, MyClass>(4, new MyClass("four")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven")),
new KeyValuePair<int, MyClass>(5, new MyClass("five")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-b")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-c")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) })
{
sorter.Insert(sortedList, kv);
}
for (int i = 0; i < sortedList.Count; i++)
{
Console.WriteLine(sortedList[i].ToString());
}
}
void Insert(List<KeyValuePair<int, MyClass>> sortedList, KeyValuePair<int, MyClass> newItem)
{
int newIndex = sortedList.BinarySearch(newItem, this);
if (newIndex < 0)
sortedList.Insert(~newIndex, newItem);
else
{
while (newIndex < sortedList.Count && (sortedList[newIndex].Key == newItem.Key))
newIndex++;
sortedList.Insert(newIndex, newItem);
}
}
#region IComparer<KeyValuePair<int,MyClass>> Members
public int Compare(KeyValuePair<int, MyClass> x, KeyValuePair<int, MyClass> y)
{
return x.Key.CompareTo(y.Key);
}
#endregion
}
Или у вас может быть отсортированный список списков:
static void Main(string[] args)
{
SortedDictionary<int, List<MyClass>> sortedList = new SortedDictionary<int,List<MyClass>>();
foreach (KeyValuePair<int, MyClass> kv in new KeyValuePair<int, MyClass>[] {
new KeyValuePair<int, MyClass>(4, new MyClass("four")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven")),
new KeyValuePair<int, MyClass>(5, new MyClass("five")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-b")),
new KeyValuePair<int, MyClass>(4, new MyClass("four-c")),
new KeyValuePair<int, MyClass>(7, new MyClass("seven-b")) })
{
List<MyClass> bucket;
if (!sortedList.TryGetValue(kv.Key, out bucket))
sortedList[kv.Key] = bucket = new List<MyClass>();
bucket.Add(kv.Value);
}
foreach(KeyValuePair<int, List<MyClass>> kv in sortedList)
{
for (int i = 0; i < kv.Value.Count; i++ )
Console.WriteLine(kv.Value[i].ToString());
}
}
Я не уверен, что вы можете использовать инициализаторы списков в .NET 2.0, как я это делал в первый пример выше, но я уверен, что вы знаете, как заполнить список данными.
Вы рассматривали класс NameValueCollection, поскольку он позволяет хранить несколько значений для каждого ключа? Например, вы можете иметь следующее:
NameValueCollection nvc = new NameValueCollection();
nvc.Add("1", "one");
nvc.Add("2", "two");
nvc.Add("3", "three");
nvc.Add("2", "another value for two");
nvc.Add("1", "one bis");
и затем для получения значений вы можете иметь:
for (int i = 0; i < nvc.Count; i++)
{
if (nvc.GetValues(i).Length > 1)
{
for (int x = 0; x < nvc.GetValues(i).Length; x++)
{
Console.WriteLine("'{0}' = '{1}'", nvc.GetKey(i), nvc.GetValues(i).GetValue(x));
}
}
else
{
Console.WriteLine("'{0}' = '{1}'", nvc.GetKey(i), nvc.GetValues(i)[0]);
}
}
что даст выход:
'1' = 'один'
'1' = 'один бис'
'2' = 'два'
'2' = 'другое значение для двух'
'3' = 'три'
Я сделал это, создав SortedList
. Когда я нахожу повторяющийся ключ, я просто вставляю значение в существующий список, связанный с ключом, уже присутствующим в объекте SortedList. Таким образом, я могу получить список значений для определенного ключа.
В .NET 2.0 вы можете написать :
List<KeyValuePair<string, string>> keyValueList = new List<KeyValuePair<string, string>>();
// Simulate your list of key/value pair which key could be duplicate
keyValueList.Add(new KeyValuePair<string,string>("1","One"));
keyValueList.Add(new KeyValuePair<string,string>("2","Two"));
keyValueList.Add(new KeyValuePair<string,string>("3","Three"));
// Here an entry with duplicate key and new value
keyValueList.Add(new KeyValuePair<string, string>("2", "NEW TWO"));
// Your final sorted list with one unique key
SortedList<string, string> sortedList = new SortedList<string, string>();
foreach (KeyValuePair<string, string> s in keyValueList)
{
// Use the Indexer instead of Add method
sortedList[s.Key] = s.Value;
}
Output :
[1, One]
[2, NEW TWO]
[3, Three]