Дисплей 1,2,3,4,5,6,8,10,11 как 1-6,8,10-11
У меня есть эта последовательность 1,2,3,4,5,6,8,10,11
Ожидаемый результат 1-6,8,10-11
Эта проблема заключается в форматировании последовательности в легко читаемой форме
Я пробовал с С# и использовал много if и else.
Интервьюер сказал, что есть простой алгоритм для этого.
Я не знаю, как добиться этого очень просто.
Также для 1,2,3 я показано 1-3. Они сказали, что это неправильно!
Существует ли какой-либо шаблон проектирования (интерпретатор) в этой логике?
Ответы
Ответ 1
Вот один из способов сделать это:
int[] numbers = { 1, 2, 3, 4, 5, 6, 8, 10, 11 };
int start, end;
for (int i = 0; i < numbers.Length; i++)
{
start = numbers[i];
while (i < numbers.Length - 1 && numbers[i] + 1 == numbers[i + 1])
i++;
end = numbers[i];
if(start == end)
Console.WriteLine(start);
else
Console.WriteLine(start + " - " + end);
}
Здесь будут отображаться последующие номера, которые растут по мере увеличения диапазона. Числа, которые не растут линейно, не записываются как часть диапазона.
Вот еще одна версия первого подхода, она использует тот же цикл for
для итерации по диапазону:
int temp = numbers[0], start, end;
for (int i = 0; i < numbers.Length; i++)
{
start = temp;
if (i < numbers.Length - 1 )
// if subsequent numbers are incremental loop further
if (numbers[i] + 1 == numbers[i + 1])
continue;
// if they are not, number at index i + 1 is a new 'start' for the next iteration
else
temp = numbers[i + 1];
end = numbers[i];
if (start == end)
Console.WriteLine(start);
else
Console.WriteLine(start + " - " + end);
}
Ответ 2
Простая реализация на С# может выглядеть так:
public string Format(IEnumerable<int> input)
{
var result = string.Empty;
var previous = -1;
var start = -1;
var first = true;
foreach(var i in input)
{
if(start == -1)
start = i;
else if(previous + 1 != i)
{
result += FormatRange(start, previous, first);
first = false;
start = i;
}
previous = i;
}
if(start != -1)
result += FormatRange(start, previous, first);
return result;
}
public string FormatRange(int start, int end, bool isFirst)
{
var result = string.Empty;
if(!isFirst)
result += ", ";
if(start == end)
result += start;
else
result += string.Format("{0}-{1}", start, end);
return result;
}
Это также выведет 1-3
для ввода 1,2,3
, что совершенно верно. Без спецификации, что должен быть выход, вместо этого невозможно ответить на эту часть.
Ответ 3
Вероятно, не подходящий ответ на вопрос о интервью, но использование LINQ - это еще один способ решить эту проблему.
int[] numbers = { 1, 2, 3, 4, 5, 6, 8, 10, 11 };
var remains = numbers.AsEnumerable();
while (remains.Any())
{
int first = remains.First();
int last = remains.TakeWhile((x, i) => x - first == i).Last();
remains = remains.Skip(last - first + 1);
Console.Write(first + (first == last ? "" : "-" + last) + (remains.Any() ? "," : Environment.NewLine));
}
Ответ 4
Код Java:
int[] arr = {1,2,3,4,5,6,8,10,11};
int start = arr[0], last = arr[0];
String output = "";
for (int i = 1; i <= arr.length; i++)
{
if (i == arr.length || arr[i] != last+1)
{
if (output.length() != 0)
output += ",";
if (start == last)
output += start;
else
output += start + "-" + last;
if (i != arr.length)
start = last = arr[i];
}
else
last = arr[i];
}
System.out.println(output);
Ответ 5
Вот моя лучшая попытка. Не умный, но достаточно простой, чтобы удовлетворить это требование, я считаю. Я все еще довольно смущен, почему "1-3" ошибается, хотя....
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 8, 10, 11, 12 };
var groups = new Dictionary<int, int>();
groups.Add(numbers.First(), numbers.First());
foreach (var num in numbers.Skip(1))
{
var grp = groups.Last();
if (grp.Value + 1 == num)
{
groups[grp.Key] = num;
}
else
{
groups.Add(num, num);
}
}
var output = string.Join(",", groups.Select(grp => (grp.Key == grp.Value) ? grp.Value.ToString() : grp.Key.ToString() + "-" + grp.Value.ToString()));
Примечание: конечно, использование словаря и linq и т.д. совершенно не нужно (и слишком специфично для ответа, требующего алгоритма), но я подумал, что он очень хорошо выделяет аспекты группировки проблемы
Ответ 6
Следующие группы объединяют целые числа и выводит строку для каждой группы. Однако он также позволяет указать минимальную длину группы, которую вы хотите перевести; все, что угодно, просто даст вам индивидуальные номера. Таким образом, если вы хотите дефинировать только группы из 4 или более человек, вы можете пройти в 4; если вы хотите деффицировать пары, вы можете пройти в 2. (Я бы хотел использовать 3 сам, но я не могу сказать, что они хотят.)
Он также не хранит никаких наборов чисел по мере их продвижения, потому что вам не нужно.
Метод:
static IEnumerable<string> Group(IEnumerable<int> input, int minLength)
{
int currentStart = int.MinValue;
int currentLength = 0;
foreach (int c in input)
{
if (currentLength > 0)
if (currentStart + currentLength == c)
currentLength++;
else
{
if (currentLength >= minLength)
yield return string.Format("{0}-{1}",
currentStart, currentStart + currentLength - 1);
else
for (int i = currentStart; i < currentStart + currentLength; i++)
yield return i.ToString();
currentStart = c;
currentLength = 1;
}
else
{
currentStart = c;
currentLength = 1;
}
}
if (currentLength >= minLength)
yield return string.Format("{0}-{1}",
currentStart, currentStart + currentLength + 1);
else
for (int i = currentStart; i < currentStart + currentLength; i++)
yield return i.ToString();
}
Использование:
int minCount = 3;
int[] input = new[] { 1, 2, 3, 4, 5, 6, 8, 10, 11 };
Console.WriteLine(String.Join(",", Group(input, minCount)));
Ответ 7
Это не действительный код С#, но чтобы показать Идею.
Отсортируйте список с Min на Max, затем сделайте следующее:
For i = Min to Max
{
if i < MaxFound
continue;
int step = 1;
Output = i;
while Found(i + Step)
{
Step++;
MaxFound = i + Step;
}
if i < MaxFound
Output = (i + "-" + MaxFound);
Output += ", ";
}
Ответ 8
Вот один из подходов:
public static void main(String[] args) {
print(1, 2, 3, 4, 5, 7, 9, 10, 12);
}
public static void print(int ... nums) {
System.out.print(nums[0]);
int idx = 1;
for(int i = 1; i < nums.length; i++, idx++) {
if(nums[i] - nums[i - 1] != 1) {
if(idx > 1) {
System.out.print(" - " + nums[i - 1]);
}
System.out.print(", " + nums[i]);
idx = 0;
}
}
if(idx > 1)
System.out.println(" - " + nums[nums.length - 1]);
}
Ответ 9
Здесь версия Haskell:
import Data.List
parseRange [] = ""
parseRange n =
let range = takeWhile (\x -> isInfixOf [x,x+1] n) n
in if not (null range)
then show (head range) ++ "-" ++ show (last range + 1)
++ (if length (tail n) > 1 then "," else "")
++ parseRange (drop (length range + 1) n)
else show (head n) ++ (if null (tail n) then "" else ",")
++ parseRange (drop 1 n)
Вывод:
*Main> parseRange [1,2,3,4,5,6,8,10,11]
"1-6,8,10-11"
Ответ 10
И способ сделать это со складыванием в F # - просто для удовольствия.
let parseRange numbers =
numbers
|> Seq.fold
(fun list n ->
match list with
|(a,b) :: tail when b+1 = n -> (a, n) :: tail
|_ -> (n,n) :: list) []
|> List.rev
|> Seq.map (fun (a,b) -> if a = b then sprintf "%i" a else sprintf "%i-%i" a b)
|> String.concat ","