C# 获取int集合的可能范围
我有一个id列表(C# 获取int集合的可能范围,c#,linq,int,range,C#,Linq,Int,Range,我有一个id列表(int)如下 是否有一种快速/智能的方式(linq?)获取所有id或范围(如果可能)? 结果应该类似于[1-3,5,7-8,11,13-14] 当然,循环和计算int值以获得结果很容易,但我确信一定有一种更简单的方法可以做到这一点。老式的方法,使用一个for循环 try { List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 }; int istart = i[0]
int
)如下
是否有一种快速/智能的方式(linq?)获取所有id或范围(如果可能)?
结果应该类似于[1-3,5,7-8,11,13-14]
当然,循环和计算int值以获得结果很容易,但我确信一定有一种更简单的方法可以做到这一点。老式的方法,使用一个for循环
try
{
List<int> i = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };
int istart = i[0];
bool flag = false;
// Use StringBuilder
for(int index = 0;index<i.Count-1;index++)
{
if ((i[index] + 1) == i[index + 1])
{
flag = true;
continue;
}
else
{
if (!flag)
Console.Write(istart);
else
Console.Write(istart + "-" + i[index]);
Console.Write(",");
flag = false;
istart = i[index + 1];
}
}
if (istart + 1 == i[i.Count - 1])
Console.Write(istart + "-" + i[i.Count - 1]);
else
Console.WriteLine(istart);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine();
Console.WriteLine("Done");
Console.Read();
试试看
{
列表i=新列表(){1,2,3,5,7,8,11,13,14};
int istart=i[0];
布尔标志=假;
//使用StringBuilder
对于(int index=0;index有一种linq方法可以做到这一点(如果数字不重复),但我不确定这是否更容易:
int last = -1;
int rank = 0;
IEnumerable<string> grouped = arr
.GroupBy(i =>
{
rank += i - last - 1;
last = i;
return rank;
})
.Select(g => g.Count() == 1 ? g.First().ToString()
: g.First().ToString() + "-" + g.Last().ToString());
守则:
int size = 10000000;
int[] arr = new int[size];
Random rnd = new Random(1);
arr[0] = 0;
for(int i = 1; i < size; ++i)
{
if (rnd.Next(100) < 25)
{
arr[i] = arr[i - 1] + 2;
}
else
{
arr[i] = arr[i - 1] + 1;
}
}
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
var res = Group(arr).ToList();
st.Stop();
MessageBox.Show(st.ElapsedMilliseconds.ToString());
MessageBox.Show(res.Sum(s => s.Length).ToString());// to be sure the work is done
int size=10000000;
int[]arr=新的int[size];
随机rnd=新随机(1);
arr[0]=0;
对于(int i=1;is.Length.ToString());//确保工作完成
免责声明这在大列表上非常慢,您也应该做一个明确的说明
这应该能奏效
static void Main(string[] args)
{
//a list with a possible of duplicate
var theList = (new int[] { 1, 2, 3, 5, 7, 8, 11, 13, 14, 13 }).OrderBy(x => x).ToList();
var step1 = theList.Select((a, b) => theList.Skip(b).TakeWhile((x, y) => a == x || theList[b + y] - 1 == theList[b + y - 1]));
var step2 = step1.GroupBy(x => x.Last())
.Select(x => x.SelectMany(y => y).Distinct())
.Select(x => x.Count() > 1 ? string.Format("{0}-{1}", x.First(), x.Last()) : x.First().ToString());
var result = string.Format("[{0}]", string.Join(", ", step2));
}
考虑到有序列表和唯一ID,我认为最简单的方法是使用classic for和while
List id=newlist(){1,2,3,5,7,8,11,13,14};
int i=0;
布尔伊斯兰格;
对于(i=0;i生成范围的逻辑是什么?为什么不是1-5、3-8等?是否有一种快速/智能的方法(linq?)-如果“快速”是指执行速度,那么“foreach”总是比linq快,你也应该在答案中加入实际的基准代码;-)@Fredou ok,adddi在我的答案中添加了一点免责声明;-)@弗雷多我同意前半部分的免责声明,但不理解“你也应该做一个与众不同的”。
simple loop: 328MB, 1.2sec
my linq: 790MB, 2.7sec
Fredous linq: 1100MB, 7days (estimated)
int size = 10000000;
int[] arr = new int[size];
Random rnd = new Random(1);
arr[0] = 0;
for(int i = 1; i < size; ++i)
{
if (rnd.Next(100) < 25)
{
arr[i] = arr[i - 1] + 2;
}
else
{
arr[i] = arr[i - 1] + 1;
}
}
System.Diagnostics.Stopwatch st = new System.Diagnostics.Stopwatch();
st.Start();
var res = Group(arr).ToList();
st.Stop();
MessageBox.Show(st.ElapsedMilliseconds.ToString());
MessageBox.Show(res.Sum(s => s.Length).ToString());// to be sure the work is done
static void Main(string[] args)
{
//a list with a possible of duplicate
var theList = (new int[] { 1, 2, 3, 5, 7, 8, 11, 13, 14, 13 }).OrderBy(x => x).ToList();
var step1 = theList.Select((a, b) => theList.Skip(b).TakeWhile((x, y) => a == x || theList[b + y] - 1 == theList[b + y - 1]));
var step2 = step1.GroupBy(x => x.Last())
.Select(x => x.SelectMany(y => y).Distinct())
.Select(x => x.Count() > 1 ? string.Format("{0}-{1}", x.First(), x.Last()) : x.First().ToString());
var result = string.Format("[{0}]", string.Join(", ", step2));
}
List<int> ids = new List<int>() { 1, 2, 3, 5, 7, 8, 11, 13, 14 };
int i = 0;
bool isrange;
for(i=0;i<ids.Count;i++)
{
isrange = false;
Console.Write(ids[i]);
while (i < ids.Count-1 && ids[i + 1] == ids[i] + 1)
{
i++;
isrange = true;
}
if (isrange)
Console.Write("-" + ids[i]);
if (!(i + 1 == ids.Count))
Console.Write(",");
}