Con esta matriz int[]{ 1, 2, 3, 4, 7, 8, 11, 15,16,17,18 };
¿Cómo puedo convertir a esta matriz de cadenas "1-4","7-8","11","15-18"
uso de LINQ para agrupar una secuencia de números sin espacios
Sugerencias? Linq?
Con esta matriz int[]{ 1, 2, 3, 4, 7, 8, 11, 15,16,17,18 };
¿Cómo puedo convertir a esta matriz de cadenas "1-4","7-8","11","15-18"
uso de LINQ para agrupar una secuencia de números sin espacios
Sugerencias? Linq?
var array = new int[] { 1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18 };
var result = string.Join(",", array
.Distinct()
.OrderBy(x => x)
.GroupAdjacentBy((x, y) => x + 1 == y)
.Select(g => new int[] { g.First(), g.Last() }.Distinct())
.Select(g => string.Join("-", g)));
con
public static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> GroupAdjacentBy<T>(
this IEnumerable<T> source, Func<T, T, bool> predicate)
{
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
var list = new List<T> { e.Current };
var pred = e.Current;
while (e.MoveNext())
{
if (predicate(pred, e.Current))
{
list.Add(e.Current);
}
else
{
yield return list;
list = new List<T> { e.Current };
}
pred = e.Current;
}
yield return list;
}
}
}
}
Gracias, esto ahorró mucho tiempo. – nRk
¿Cuál es el algoritmo que desea implementar? Averigüe qué quiere que suceda, luego vea si podría hacerse más claro con una traducción LINQ. Aquí hay algo que no es LINQ que podría darte una idea.
int[] array = { 1, 2, 3, 4, 7, 8, 11, 15, 16, 17, 18};
List<string> ranges = new List<string>();
// code assumes array is not zero-length, is distinct, and is sorted.
// to do: handle scenario as appropriate if assumptions not valid
Action<int, int, List<string>> addToRanges = (first, last, list) =>
{
if (last == first)
list.Add(last.ToString());
else
list.Add(string.Format("{0}-{1}", first, last)); ;
};
int firstItem = array[0];
int lastItem = firstItem;
foreach (int item in array.Skip(1))
{
if (item > lastItem + 1)
{
addToRanges(firstItem, lastItem, ranges);
firstItem = lastItem = item;
}
else
{
lastItem = item;
}
}
addToRanges(firstItem, lastItem, ranges);
// return ranges or ranges.ToArray()
Quiero implementar lo que es más claro, estaba intentando algo con linq group pero sin éxito – Alexandre
No es necesario LINQ; de hecho, la solución más fácil requiere conocer tres posiciones en la matriz (su número inicial, número actual y el siguiente número después de la actual), para los cuales los Enumerables no son adecuados.
Prueba esto:
var start = 0;
var end = 0;
var write = false;
var builder = new StringBuilder();
for(var i=0; i<array.Length; i++)
{
//arranged this way to avoid ArrayOutOfBoundException
//if the next index doesn't exist or isn't one greater than the current,
//the current index is the end of our incremental range.
if(i+1 == array.Length || array[i+1] > array[i] + 1)
{
end = i;
write = true;
}
if(write)
{
if(end - start == 0) //one number
builder.Append(String.Format("{0}, ", array[start]);
else //multi-number range
builder.Append(String.Format("{0}-{1}, ", array[start], array[end]);
start = i+1;
end = i+1; //not really necessary but avoids any possible case of counting backwards
write = false;
}
}
puede reorganizar esto para reducir la anidación de código, continue
principios de la lógica de bucle, y quitar unos VARs; ganarás unos mil millones de tiempo de ejecución. También deberá recortar los dos últimos caracteres (una coma y un espacio al final) del extremo del StringBuilder antes de sacar el String.
_¿No necesita Linq_? Si bien su versión es totalmente correcta, una solución ideológica LINQ también tiene la ventaja de que puede portar fácilmente una solución de este tipo a cualquier lenguaje de programación funcional, como F # o Haskell. – mbx
Aquí es un corte en él:
public static IEnumerable<string> ToRanges(this IEnumerable<int> values)
{
int? start = null, end = null;
foreach (var value in values.OrderBy(vv => vv))
{
if (!start.HasValue)
{
start = value;
}
else if (value == (end ?? start) + 1)
{
end = value;
}
else
{
yield return end.HasValue
? String.Format("{0}-{1}", start, end)
: String.Format("{0}", start);
start = value;
end = null;
}
}
if (start.HasValue)
{
yield return end.HasValue
? String.Format("{0}-{1}", start, end)
: String.Format("{0}", start);
}
}
es la secuencia siempre en orden ascendente? ¿Puede haber duplicados? – Ani