我有一组数据,我想从特定的数字开始重新订购,然后,当达到最高数字时,返回最低数据然后继续递增。
例如,对于序列(1,2,3,4,5,6),如果4是特定数字,则顺序将变为(4,5,6,1,2,3)。
这可能与linq& C#?
答案 0 :(得分:26)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6 };
int num = 4;
var newList = list.SkipWhile(x=>x!=num)
.Concat(list.TakeWhile(x=>x!=num))
.ToList();
答案 1 :(得分:10)
int specific = 4;
var numbers = Enumerable.Range(1, 9);
var result = numbers.OrderBy(n => Tuple.Create(n < speficic, n)).ToList();
我在这里使用了一个小技巧,使用Tuple<bool, int>
作为比较器,因为false < true
。另一种选择是:
var result = numbers.OrderBy(n => n < speficic).ThenBy(n => n).ToList();
在基准测试之后 编辑我发现第二个解决方案.OrderBy .ThenBy
比Tuple
解决方案快得多。我相信这是因为FCL使用Comparer<T>.Default
作为比较器,这需要花费时间来构建。
答案 2 :(得分:4)
OrderBy()
本身非常强大,而且为了扩大其范围,ThenBy()
因此,我认为更清洁的方法如下:
var list = new[] {1, 2, 3, 4, 5, 6};
var pivot = 4;
var order = list.OrderBy(x => x == pivot ? 0 : 1).ThenBy(y => y < pivot ? 1: 0);
答案 3 :(得分:3)
您可以实施自定义IComparer。
如下所示(注意代码未经过测试!):
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6 };
list.OrderBy(n => n, new IntComparer(4));
public class IntComparer : IComparer<int>
{
int start;
public IntComparer (int start)
{
this.start = start;
}
// Compares by Height, Length, and Width.
public int Compare(int x, int y)
{
if (x >= start && y < start)
// X is greater than Y
return 1;
else if (x < start && y >= start)
// Y is greater than X
return -1;
else if (x == y)
return 0;
else
return x > y ? 1 : -1;
}
}
答案 4 :(得分:2)
List<int> list = new List<int>() { 1, 2, 3, 4, 5, 6 };
item = 4;
var index = input.IndexOf(item);
var firstList = input.Take(index);
return input.Except(firstList)
.Concat(firstList)
.ToList();
答案 5 :(得分:2)
对于一般情况,以下是任何类的自定义IComparer
。
public class StartWithComparer<T> : IComparer<T>
{
private T startWith;
private IComparer<T> baseComparer = Comparer<T>.Default;
public StartWithComparer(T startWith, IComparer<T> baseComparer = null)
{
this.startWith = startWith;
if (baseComparer != null) this.baseComparer = baseComparer;
}
public int Compare(T x, T y)
{
int xToS = baseComparer.Compare(x, startWith);
int yToS = baseComparer.Compare(y, startWith);
if (xToS >= 0 && yToS < 0)
return -1;
else if (xToS < 0 && yToS >= 0)
return 1;
else
return baseComparer.Compare(x, y);
}
}
由
调用new[] { 1, 2, 3, 4, 5, 6 }.OrderBy(i => i, new StartWithComparer<int>(4))
答案 6 :(得分:1)
您可以使用(或滥用,我承认)一个简单的减法来实现这一目标:
var seq = Enumerable.Range(0, 10);
int n = 4;
int m = seq.Max() + 1; // or a magic number like 1000, thanks RB.
var ordered = seq.OrderBy(x => x >= n ? x - m : x);
foreach(int i in ordered)
Console.WriteLine(i);
此外,如果数字变大,请注意整数溢出。对于简单的情况,它可能没问题。
这是一个更好的解决方案(受到其他答案的启发):
var seq = Enumerable.Range(0, 10);
int n = 4;
var ordered = seq.Where(x => x >= n).OrderBy(x => x)
.Concat(seq.Where(x => x < n).OrderBy(x => x));
foreach(int i in ordered)
Console.WriteLine(i);
对每个序列进行排序。在连接它们之前。 T_12在评论中询问他们是否按升序排序。如果是,请使用L.B.'s solution而不是我的,因为OrderBy
将努力至少O(n log n)
而不是O(n)
(线性)。
答案 7 :(得分:1)
List<int> list = new List<int>()
{
1,2,3,4,5,6
};
int number = 4;
int max = list.Max();
var result = list.OrderBy(i => i >= number ? i : max + i);
答案 8 :(得分:1)
我会在这里提出一个异端解决方案,因为它根本没有使用标准的LINQ运算符:
IEnumerable<int> GetSequence(IList<int> input, int index) {
for (var i = index; i < input.Count; i++) yield return input[i];
for (var i = 0; i < index; i++) yield return input[i];
}
我认为这很清楚地表明了意图。
我不认为您必须使用标准LINQ查询运算符(Skip,Take,Concat的组合)执行的奇怪扭曲是可读或可维护的。我认为仅仅是为了它而在这种情况下使用它们是一种滥用。循环很好。
答案 9 :(得分:1)
将序列移动到给定项目开始的扩展方法。这也只会通过原始序列一次,这可能重要也可能不重要。这也假设序列已经按照你想要的方式排序,除了移位。
public static IEnumerable<T> Shift<T>(this IEnumerable<T> subject, T shouldBeFirst)
{
return subject.Shift(shouldBeFirst, EqualityComparer<T>.Default);
}
public static IEnumerable<T> Shift<T>(this IEnumerable<T> subject, T shouldBeFirst, IEqualityComparer<T> comparer)
{
var found = false;
var queue = new Queue<T>();
foreach (var item in subject)
{
if(!found)
found = comparer.Equals(item, shouldBeFirst);
if(found)
yield return item;
else
queue.Enqueue(item);
}
while(queue.Count > 0)
yield return queue.Dequeue();
}
<强>用法强>
var list = new List<int>() { 1, 2, 3, 4, 5, 6 };
foreach (var i in list.Shift(4))
Console.WriteLine(i);
<强>打印强>
4
5
6
1
2
3
答案 10 :(得分:0)
如果您的数据是List<T>
,则可以使用
var sequence = new[] { 1, 2, 3, 4, 5, 6 }.ToList();
List<int> result;
int start = 4;
int index = sequence.IndexOf(start);
if (index == 0)
result = sequence;
else if (index > -1)
{
result = sequence.GetRange(index, sequence.Count - index);
var secondPart = sequence.GetRange(0, sequence.Count - index);
result.AddRange(secondPart);
}
这不是真正订购,而是创建一个新列表。