보고서에 다양한 개체가 나타나는 순서를 설정하는 프로그램을 작성 중입니다. 시퀀스는 Excel 스프레드 시트의 Y 위치 (셀)입니다.
코드의 데모 부분은 다음과 같습니다. 내가 달성하고 싶은 것은 컬렉션을 갖는 것입니다. 이렇게하면 여러 개체를 추가 할 수 있고 시퀀스에 따라 정렬 된 컬렉션을 얻을 수 있습니다.
SortedList list = new SortedList();
Header h = new Header();
h.XPos = 1;
h.name = "Header_1";
list.Add(h.XPos, h);
h = new Header();
h.XPos = 1;
h.name = "Header_2";
list.Add(h.XPos, h);
나는 SortedList가 이것을 허용하지 않을 것이라는 것을 알고 있으며 대안을 찾고 있습니다. 중복 을 제거 하고 싶지 않고 이미 시도했습니다 List<KeyValuePair<int, object>>
.
감사.
답변
나만의 IComparer를 사용하세요!
다른 답변에서 이미 언급했듯이 자신의 비교 자 클래스를 사용해야합니다. 이를 위해 IComparable을 구현하는 모든 것과 함께 작동하는 일반 IComparer 클래스를 사용합니다.
/// <summary>
/// Comparer for comparing two keys, handling equality as beeing greater
/// Use this Comparer e.g. with SortedLists or SortedDictionaries, that don't allow duplicate keys
/// </summary>
/// <typeparam name="TKey"></typeparam>
public class DuplicateKeyComparer<TKey>
:
IComparer<TKey> where TKey : IComparable
{
#region IComparer<TKey> Members
public int Compare(TKey x, TKey y)
{
int result = x.CompareTo(y);
if (result == 0)
return 1; // Handle equality as beeing greater
else
return result;
}
#endregion
}
새 SortedList, SortedDictionary 등을 인스턴스화 할 때 사용합니다.
SortedList<int, MyValueClass> slist = new SortedList<int, MyValueClass>(new DuplicateKeyComparer<int>());
여기서 int는 중복 될 수있는 키입니다.
답변
List <>를 안전하게 사용할 수 있습니다. List에는 IComparer를 허용하는 오버로드 인 Sort 메서드가 있습니다. 고유 한 분류기 클래스를. 다음은 예입니다.
private List<Curve> Curves;
this.Curves.Sort(new CurveSorter());
public class CurveSorter : IComparer<Curve>
{
public int Compare(Curve c1, Curve c2)
{
return c2.CreationTime.CompareTo(c1.CreationTime);
}
}
답변
다음을 사용합니다.
public class TupleList<T1, T2> : List<Tuple<T1, T2>> where T1 : IComparable
{
public void Add(T1 item, T2 item2)
{
Add(new Tuple<T1, T2>(item, item2));
}
public new void Sort()
{
Comparison<Tuple<T1, T2>> c = (a, b) => a.Item1.CompareTo(b.Item1);
base.Sort(c);
}
}
내 테스트 케이스 :
[TestMethod()]
public void SortTest()
{
TupleList<int, string> list = new TupleList<int, string>();
list.Add(1, "cat");
list.Add(1, "car");
list.Add(2, "dog");
list.Add(2, "door");
list.Add(3, "elephant");
list.Add(1, "coconut");
list.Add(1, "cab");
list.Sort();
foreach(Tuple<int, string> tuple in list)
{
Console.WriteLine(string.Format("{0}:{1}", tuple.Item1,tuple.Item2));
}
int expected_first = 1;
int expected_last = 3;
int first = list.First().Item1; //requires using System.Linq
int last = list.Last().Item1; //requires using System.Linq
Assert.AreEqual(expected_first, first);
Assert.AreEqual(expected_last, last);
}
출력 :
1:cab
1:coconut
1:car
1:cat
2:door
2:dog
3:elephant
답변
문제는 데이터 구조 설계가 요구 사항과 일치하지 않는다는 것입니다. 동일한 XPos에 대해 여러 헤더를 저장해야합니다. 따라서 SortedList<XPos, value>
의 값이 Header
아니라 값을 가져야합니다 List<Header>
. 간단하고 사소한 변경이지만 모든 문제를 해결하고 다른 제안 된 솔루션과 같은 새로운 문제를 생성하지 않습니다 (아래 설명 참조).
using System;
using System.Collections.Generic;
namespace TrySortedList {
class Program {
class Header {
public int XPos;
public string Name;
}
static void Main(string[] args) {
SortedList<int, List<Header>> sortedHeaders = new SortedList<int,List<Header>>();
add(sortedHeaders, 1, "Header_1");
add(sortedHeaders, 1, "Header_2");
add(sortedHeaders, 2, "Header_3");
foreach (var headersKvp in sortedHeaders) {
foreach (Header header in headersKvp.Value) {
Console.WriteLine(header.XPos + ": " + header.Name);
}
}
}
private static void add(SortedList<int, List<Header>> sortedHeaders, int xPos, string name) {
List<Header> headers;
if (!sortedHeaders.TryGetValue(xPos, out headers)){
headers = new List<Header>();
sortedHeaders[xPos] = headers;
}
headers.Add(new Header { XPos = xPos, Name = name });
}
}
}
Output:
1: Header_1
1: Header_2
2: Header_3
임의의 숫자를 추가하거나 동일한 값을 가진 2 개의 XPos가 다른 것처럼 가장하는 것과 같은 “재미있는”키를 추가하면 다른 많은 문제가 발생합니다. 예를 들어 특정 헤더를 제거하는 것이 어렵거나 불가능 해집니다.
또한 List<Header>
모든 .NET보다 소수만 정렬해야하는 경우 정렬 성능이 훨씬 더 좋습니다 Header
. 예 : XPos가 100 개이고 각각 헤더가 100 개인 경우 100이 아니라 10000 Header
을 정렬해야합니다.List<Header>
.
물론이 솔루션에도 단점이 있습니다. 헤더가 1 개만있는 XPos가 많으면 목록을 많이 만들어야하므로 약간의 오버 헤드가 발생합니다.
답변
가장 간단한 솔루션 (위의 모든 것과 비교) :을 사용 SortedSet<T>
하고 IComparer<SortableKey>
클래스를 허용 한 다음 다음과 같이 Compare 메서드를 구현합니다.
public int Compare(SomeClass x, SomeClass y)
{
var compared = x.SomeSortableKeyTypeField.CompareTo(y.SomeSortableKeyTypeField);
if (compared != 0)
return compared;
// to allow duplicates
var hashCodeCompare = x.GetHashCode().CompareTo(y.GetHashCode());
if (hashCodeCompare != 0)
return hashCodeCompare;
if (Object.ReferenceEquals(x, y))
return 0;
// for weird duplicate hashcode cases, throw as below or implement your last chance comparer
throw new ComparisonFailureException();
}
답변
도와 주셔서 정말로 고맙습니다. 더 많이 검색하는 동안이 해결책을 찾았습니다. (다른 질문은 Stackoverflow.com에서 사용 가능)
먼저 클래스 (Headers, Footer 등)에 대한 개체를 캡슐화하는 클래스를 만들었습니다.
public class MyPosition
{
public int Position { get; set; }
public object MyObjects{ get; set; }
}
따라서이 클래스는 객체를 보유해야하며 각 객체의 PosX는 int Position으로 이동합니다.
List<MyPosition> Sequence= new List<MyPosition>();
Sequence.Add(new MyPosition() { Position = 1, Headerobject });
Sequence.Add(new MyPosition() { Position = 2, Headerobject1 });
Sequence.Add(new MyPosition() { Position = 1, Footer });
League.Sort((PosA, PosB) => PosA.Position.CompareTo(PosB.Position));
결국 내가 얻는 것은 정렬 된 “시퀀스”목록입니다.