16

私はこのシーケンスを持っています1,2,3,4,5,6,8,10,11

期待される出力は1-6,8,10-11 です

この問題は、シーケンスを読みやすい形式にフォーマットすることに関するものです

私はC#で試してみて、多くのif&elseを使用しました。

インタビュアーは、これを行うための簡単なアルゴリズムがあると言いました。

これを非常に簡単に達成する方法がわかりません。

また、1,2,3については1-3を示しました。彼らはそれが間違っていると言った!

このロジックに関連する設計パターン (インタープリター) はありますか?

4

10 に答える 10

16

これを行う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);
        }
于 2013-02-19T08:34:40.587 に答える
5

C# での単純な実装は次のようになります。

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これはinput に対しても出力されます1,2,3が、これは完全に有効です。出力がどうあるべきかの仕様がなければ、その部分に答えるのは不可能です。

于 2013-02-19T08:35:12.907 に答える
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));
}
于 2013-02-19T10:07:43.467 に答える
2

これが私の最善の試みです。賢くはありませんが、私が信じるその要件を満たすのに十分シンプルです。なぜ「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などを使用する必要はまったくありません(アルゴリズムを必要とする回答にはあまりにも具体的です)が、問題のグループ化の側面をうまく強調していると思いました

于 2013-02-19T08:47:54.807 に答える
2

次の例では、連続する整数をグループ化し、グループごとに文字列を出力します。ただし、ハイフネーションするグループの最小の長さを指定することもできます。それ以下の場合は、個々の番号が表示されます。したがって、4 つ以上のグループのみをハイフネーションしたい場合は、4 を渡すことができます。ペアをハイフネーションしたい場合は、2 を渡すことができます

また、必要がないため、進行中に数値のコレクションを保持しません。

方法:

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)));
于 2013-02-19T08:49:15.447 に答える
2

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);
于 2013-02-19T08:31:24.027 に答える
1

アプローチの1つは次のとおりです。

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]);
}
于 2013-02-19T08:45:17.710 に答える
1

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"
于 2013-02-19T22:28:04.203 に答える
1

これは有効な C# コードではなく、アイデアを示すためのものです。

リストを最小から最大に並べ替えてから、次のようにします。

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 += ", ";
}
于 2013-02-19T08:35:36.483 に答える
0

そして、F# の fold でそれを行う方法 - ただの楽しみです。

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 ","
于 2013-12-16T14:30:32.263 に答える