Linq 문제

μ½”λ“œλ₯Ό μ§œλ‹€κ°€ λ§Œλ‚œ λ‚œμ œμž…λ‹ˆλ‹€.
λ‹€λ₯Έ 뢄듀은 μ–΄λ–»κ²Œ ν•˜μ‹œλŠ” μ§€ 문득 κΆκΈˆν•΄μ‘ŒμŠ΅λ‹ˆλ‹€.

문제

κ²°κ³Ό μ˜ˆμ‹œμ²˜λŸΌ, μ •μˆ˜ μ‹œν€€μŠ€μ—μ„œ λΆ€λΆ„μ μœΌλ‘œ μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ—°μ†ν•˜λŠ” μ‹œν€€μŠ€μ˜ 첫 μ •μˆ˜λ§Œ μΆ”μΆœν•˜λŠ” LInq λ©”μ„œλ“œλ₯Ό μž‘μ„±ν•˜μ‹œμ˜€. 단, μž…λ ₯값은 정렬됨을 보μž₯ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

IEnumerable<int> Extract(IEnumerable<int> numbers)
{
   // μ½”λ“œ
}

κ²°κ³Ό μ˜ˆμ‹œ

μž…λ ₯: { 1, 2, 5, 6, 8, 9, 10, ... } 
좜λ ₯: { 1,    5,    8, ... }
5개의 μ’‹μ•„μš”

μž…λ ₯ 값은 μ •λ ¬λ˜μ—ˆλ‹€κ³  κ°€μ • ν•˜λ‚˜μš”?

4개의 μ’‹μ•„μš”

λ”°μ§€μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
λΆ€λΆ„ μ—°μ†μ΄λž€ μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μ—°μ†λœ κ²ƒμž…λ‹ˆλ‹€.

4개의 μ’‹μ•„μš”

μ—°μ†λœ μˆ«μžλŠ” κ³ λ € ν•˜μ§€ μ•Šκ³  λ‹¨μˆœνžˆ

IEnumerable<int> Extract(IEnumerable<int> numbers)
{
            int? prev = null;
            foreach (int number in numbers)
            {
                if (prev == null || number != prev + 1)
                {
                    yield return number;
                }
                prev = number;
            }
}

var result = Extract(
    new List<int> { -1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10 };
);

[κ²°κ³Ό]

-1, -1, -2, 4, 8, 8
6개의 μ’‹μ•„μš”

μ•„μ‰½μŠ΅λ‹ˆλ‹€.
예제의 μž…λ ₯κ³Ό μš”κ΅¬ν•˜λŠ” 좜λ ₯μž…λ‹ˆλ‹€.

μž…λ ₯: { -1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10 }
좜λ ₯: { -2, 4, 8 }
4개의 μ’‹μ•„μš”

생각보닀 μ½”λ“œκ°€ κ°„λ‹¨ν•˜κ²ŒλŠ” μ•ˆλ‚˜μ˜€λ„€μš”.

IEnumerable<int> numbers = [1, 2, 5, 6, 8, 9, 10];
var result = numbers.Extract();
Console.WriteLine($"[{string.Join(", ", result)}]");

IEnumerable<int> numbers2 = [-1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10];
var result2 = numbers2.Extract();
Console.WriteLine($"[{string.Join(", ", result2)}]");


static class LinqMethodExtension
{
    public static IEnumerable<int> Extract(this IEnumerable<int> @this)
    {
        int? prev = null;
        var distance = 0;
        foreach (var item in @this)
        {
            prev ??= item;

            if (item == prev + distance)
                distance++;
            else
            {
                if (distance > 1)
                    yield return prev.Value;
                prev = item;
                distance = 1;
            }
        }

        if (distance > 1 && prev is not null)
        {
            yield return prev.Value;
        }
    }
}

| 좜λ ₯

[1, 5, 8]
[-2, 4, 8]
5개의 μ’‹μ•„μš”

μš°μ„  제 μŠ€νƒ€μΌλ‘œ λŒ€μΆ© μ½”λ“œλ₯Ό 짜보면 μ•„λž˜μ™€ 같이 λ‚˜μ˜€λ„€μš”

using System.Linq;

IEnumerable<int> Extract(IEnumerable<int> numbers)
{
    bool findFlag = false;

    for (int i = 0; i < (numbers.Count() - 1); ++i)
    {

        int current = numbers.ElementAt(i);
        int next = numbers.ElementAt(i + 1);

        if ((next - current) is 1)
        {
            if (!findFlag)
            {
                findFlag = true;

                yield return current;
            }
            else
            {
                continue;
            }
        }
        else
        {
            findFlag = false;
        }
    }
}

List<int> target = new() { -1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10 };
List<int> result = Extract(target).ToList();

result.ForEach(x => Console.WriteLine($"{x} "));

λ‚΄λΆ€ κ΅¬ν˜„μ„ LINQ둜 μ²˜λ¦¬ν•΄λ³΄κ³  싢은데…아직 LINQ μ‹€λ ₯이 햇병아리인지라 κ΅¬ν˜„μ΄ μ–΄λ ΅λ„€μš” γ…œγ…œ

4개의 μ’‹μ•„μš”
List<int> list = [-1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10];
Console.WriteLine(string.Join(", ", Extract(list)));
// output: -2, 4, 8
IEnumerable<int> Extract(IEnumerable<int> numbers)
{
    return numbers.Distinct()
        .Order()
        .Select(x => (Key: x, Result: Enumerable.Repeat(x, 1)))
        .Aggregate((prev, next) => prev.Key + 1 == next.Key ? (next.Key, prev.Result) : (next.Key, prev.Result.Concat(next.Result)))
        .Result;
}

순수 linqλ§Œμ„ μ΄μš©ν•˜λ €λ©΄ μ΄λ ‡κ²Œλ„ κ°€λŠ₯ν•©λ‹ˆλ‹€.

6개의 μ’‹μ•„μš”

쒋은 μ½”λ“œλ‘œ μ°Έμ—¬ κ°μ‚¬λ“œλ¦½λ‹ˆλ‹€.

그런데, μž…λ ₯값이 IEnumerable인데, μ»¬λ ‰μ…˜μœΌλ‘œ κ°€μ •ν•˜μ‹  것 κ°™μŠ΅λ‹ˆλ‹€.
(@URK96 λ‹˜λ„ λ™μΌν•©λ‹ˆλ‹€)

즉, 보여 μ£Όμ‹  μ½”λ“œλŠ”, μž…λ ₯이 μ•„λž˜μ™€ 같은 κ²½μš°μ—λŠ” 값을 λ°˜ν™˜ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

IEnumerable<int> Numbers()
{
    while(true)
   {
      if (int.TryParse(Console.ReadLine(), out var number))
         yield return number;
   }
}
foreach (var n in Extract(Numbers()))
{
    Console.WriteLine(n); // μ‹€ν–‰λ˜μ§€ μ•ŠμŒ.
}

@dimohy λ‹˜μ˜ μ½”λ“œλŠ” κ·ΈλŸ¬ν•œ 가정이 없기에 정상 λ™μž‘ν•©λ‹ˆλ‹€.

5개의 μ’‹μ•„μš”

저도 μ΅œλŒ€ν•œ κ°„λ‹¨ν•˜κ²Œ ν•œ 번 :grin:

static IEnumerable<int> Extract(IEnumerable<int> numbers)
{
    var prev = numbers.FirstOrDefault();
    var prePrev = prev;
    foreach (var current in numbers.Skip(1))
    {
        if (prePrev + 1 != prev && prev + 1 == current)
            yield return prev;
        (prePrev, prev) = (prev, current);
    }
}

μ½˜μ†” μž…μΆœλ ₯

-1
-1
-2
-1
>> -2
0
1
2
4
5
>> 4
6
8
8
9
>> 8
10
8개의 μ’‹μ•„μš”

μ•—, μž…λ ₯으둜 yield return이 λ“€μ–΄μ˜€λŠ” CaseλŠ” κ³ λ €λ₯Ό λͺ»ν–ˆλ„€μš”…

λ‹¨μˆœ ν˜ΈκΈ°μ‹¬μœΌλ‘œ μ°Έμ—¬ν–ˆλ˜ 글인데 μ˜ˆμƒμΉ˜ λͺ»ν•˜κ²Œ ν•˜λ‚˜ λ°°μ›Œκ°€λ„€μš” κ°μ‚¬ν•©λ‹ˆλ‹€ :slight_smile:

4개의 μ’‹μ•„μš”

μ»¬λ ‰μ…˜κ³Ό μ‹œν€€μŠ€λ₯Ό λΆ„λ¦¬ν•΄μ„œ μΆ”μƒν™”ν•œ 주도 λ©΄λ°€ν•œ λ§ˆμ†Œλ†ˆλ“€ λ•Œλ¬Έμ΄μ£ . ^^

4개의 μ’‹μ•„μš”
    static void Main(string[] args)
    {
        //List<int> target = [-1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10];
        List<int> target = [1, 2, 5, 6, 8, 9, 10];
        var result = target.Split(x =>
        {
            if (x == 0)
            {
                if (target[x + 1] == (target[x] + 1))
                    return true;
            }
            else if (target[x - 1] != (target[x] - 1))
                return true;
            return false;
        }).Where(x => x.Count() > 1).Select(x => x.First());

        foreach (var item in result)
            Console.WriteLine(item);
    }

public static class LinqExtention
{
    public static IEnumerable<IEnumerable<TSource>> Split<TSource>(this IEnumerable<TSource> source, Func<int, bool> selector)
    {
        int? start = null;
        for (int i = 0; i < source.Count(); ++i)
        {
            if (selector(i))
            {
                if (start == null)
                {
                    start = i;
                }
                else
                {
                    var temp = start;
                    start = i;
                    yield return source.Skip(temp.Value).SkipLast(source.Count()-i);
                }
            }
        }
        if (start < source.Count())
            yield return source.Skip(start.Value);
    }
}

생각보닀 κΈ°λ„€μš”β€¦;;

PS : Extract 라고 λ§Œλ“œλŠ” κ±°μ˜€λ„€μš”β€¦;; λ‚œλ…μ¦μ΄β€¦;;

5개의 μ’‹μ•„μš”
        IEnumerable<int> Extract(IEnumerable<int> numbers)
        {
            return numbers.Select((x, i) => new { x, i })
                .GroupBy(x => x.x - x.i)
                .Where(i => i.Count() > 1)
                .SelectMany(item => item.Select((x, i) => new { x.x, i })
                    .GroupBy(x => x.x - x.i)
                    .Where(i => i.Count() > 1)
                    .Select(i => i.First().x));
        }

Linq 만 μ¨μ„œ μ§œλ΄€λŠ”λ° λ³΅μž‘ν•΄μ„œ λ§ˆμŒμ— μ•ˆλ“œλ„€μš”.

5개의 μ’‹μ•„μš”

μ°Έμ—¬ κ°μ‚¬ν•©λ‹ˆλ‹€.
그런데, λ™μž‘ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.
GroupBy λ•Œλ¬ΈμΈ 것 κ°™μŠ΅λ‹ˆλ‹€.

3개의 μ’‹μ•„μš”

제 μ»΄ν“¨ν„°μ—μ„œλŠ” μž˜λ˜λŠ” 데 μ΄μƒν•˜λ„€μš”.

3개의 μ’‹μ•„μš”

μž…λ ₯을 μ•„λž˜ μ½”λ“œλ‘œ λŒ€μ²΄ν•΄λ³΄μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

IEnumerable<int> Numbers()
{
    while(true)
   {
      if (int.TryParse(Console.ReadLine(), out var number))
         yield return number;
   }
}
4개의 μ’‹μ•„μš”

Linq λ©”μ„œλ“œλŠ” μ•„λ‹ˆμ§€λ§Œ, ν˜„μž¬κΉŒμ§€ μ œμ‹œλœ μ½”λ“œ 쀑, μœ μΌν•˜κ²Œ 정상 λ™μž‘ν•˜λŠ” μ½”λ“œμž…λ‹ˆλ‹€. κ·Έ 짧은 μ‹œκ°„μ— λŒ€λ‹¨ν•˜μ‹­λ‹ˆλ‹€. :clap:t3: :clap:t3: :clap:t3:
μ €λŠ” 거의 λ°˜λ‚˜μ ˆ κ±Έλ ΈμŠ΅λ‹ˆλ‹€.

List<int> list = [-1, -1, -2, -1, 0, 1, 2, 4, 5, 6, 8, 8, 9, 10];

IEnumerable<int> Numbers()
{
   while(true)
   {
      if (int.TryParse(Console.ReadLine(), out var number))
         yield return number;
   }
}

var results = Extract(list);
results = Extract([]);
results = Extract(Numbers());
3개의 μ’‹μ•„μš”

μ—‡ μ œκΊΌλ„ λ™μž‘ μ•ˆν•˜λ‚˜μš”??

4개의 μ’‹μ•„μš”

예. μ‹€νŒ¨ μΌ€μ΄μŠ€κ°€ μžˆμŠ΅λ‹ˆλ‹€.
보여주신 μž…λ ₯ 데이터가 이 μΌ€μ΄μŠ€λ₯Ό 숨기고 μžˆλŠ”λ°, 원인은 두 번째 μš”μ†Œμ˜ μ²˜λ¦¬μ™€ 관련이 μžˆμŠ΅λ‹ˆλ‹€.

3개의 μ’‹μ•„μš”