2017-11-12 3 views
1

문자열 목록 (예 : 문자열을 예로 든 것)이 있다고 가정합니다.비동기식 술어를 사용하여 목록을 필터링하는 방법

IEnumerable<string> fullList = ...; 

과 같은 비동기 술어입니다.

static Task<bool> IncludeString(string s) { ... } 

다음과 같은 제약, 술어하여 목록을 필터링하는 가장 간단한 방법은 무엇 :

  1. 조건부 실행하지 않아야 순차적으로 (목록이 긴 및 비동기 술어가 느린 가정은)
  2. 나는 해결책을 찾을 않았다

주문 보존한다 필터링 된 목록을 결과

  • ,하지만 PRED의 결과가 임시 목록을 작성 포함 각 항목에 대해 퀴즈를 작성한 다음이를 사용하여 필터링을 수행하십시오. 그것은 단지 충분히 우아하게 느끼지 않습니다. 여기에 있습니다 :

    var includedIndices = await Task.WhenAll(fullList.Select(IncludeString)); 
    var filteredList = fullList.Where((_, i) => includedIndices[i]); 
    

    간단한 프레임 워크 호출에서 가능해야하지만 뭔가를 찾을 수 없었습니다. 당신은 당신이 필요로하는 Linq 기능 당신 자신의 구현을 만들 수

  • +0

    그러나 ParallelLinq는 여러 개의 비동기 작업을 동시에 기다리는 대신 많은 스레드를 사용하지 않습니다. 그래서 그것은 작동하지 않을 것이라고 말하지만, 그것은 무거운 무게일지도 모릅니다. –

    답변

    1

    특별히 우아하지는 않지만 선택 영역의 Task.ContinueWith 호출에서 익명 형식을 만들고 해당 배열에서 WhenAll 호출을 기다리고 해당 작업 결과에 포함 된 값을 사용할 수 있습니다. 열거시에도 ToArray 호출, 반환되는 열거 의지하지 않고 하지이 열거 소스를 다시 열거

    // Returns { "ab", "abcd" } after 1000ms 
    string[] evenLengthStrings = await FilterAsync<string>(new string[] { "a", "ab", "abc", "abcd" }, (async s => { await Task.Delay(1000); return s.Length % 2 == 0; })); 
    

    주 - 그것을 :

    public async Task<T[]> FilterAsync<T>(IEnumerable<T> sourceEnumerable, Func<T, Task<bool>> predicateAsync) 
    { 
        return (await Task.WhenAll(
         sourceEnumerable.Select(
          v => predicateAsync(v) 
          .ContinueWith(task => new { Predicate = task.Result, Value = v }))) 
         ).Where(a => a.Predicate).Select(a => a.Value).ToArray(); 
    } 
    

    사용 예제 (시연했다-up 기능) Task.WhenAll은 LINQy lazy 열거 형을 반환하지 않기 때문에 게으르지 않을 것입니다.

    +0

    더 기능적이므로 조금 더 청소하십시오.IEnumerable 및 술어를 사용하는 일반 도우미로 다시 작성하고 한 줄에 모든 것이 없도록 조금 정리하면 답변으로 표시됩니다. 감사! –

    +0

    이제 일반화되고 올바르게 술어를 사용합니다. 여전히 한 문장이지만 원하는 경우 임시 게으른 열거자를 별도의 줄로 구분할 수 있습니다. – glen3b

    +0

    나에게 충분하다. 고마워! –

    1

    , 즉

    public static async Task<IEnumerable<TIn>> FilterAsync<TIn>(this IEnumerable<TIn> source, Func<TIn, Task<bool>> action) 
    { 
        if (source == null) throw new ArgumentNullException(nameof(source)); 
        if (action == null) throw new ArgumentNullException(nameof(action)); 
    
        var result = new List<TIn>(); 
        foreach (var item in source) 
        { 
         if (await action(item)) 
         { 
          result.Add(item); 
         } 
        } 
    
        return result; 
    } 
    

    그런 다음이 구현 주어진 그래서

    IEnumerable<string> example = new List<string> { "a", "", null, " ", "e" }; 
    var validStrings = await example.FilterAsync(IncludeString); 
    // returns { "a", "e" } 
    

    처럼 사용할 수 있습니다 IncludeString

    public static Task<bool> IncludeString(string s) { 
        return Task.FromResult(!string.IsNullOrWhiteSpace(s)); 
    } 
    

    기본적으로 이것은 async Func<int, Task<bool>>입니다. 목록의 각 항목에 대해

    +0

    구현시 각 항목에 대해 술어가 순차적으로 실행되므로 매우 느리게 실행됩니다. 질문에 나열된 제약 조건을 참조하십시오. –

    +0

    필터 여야하나요? 동시 필터가 같은 컬렉션에서 작동 할 때 무결성을 어떻게 보장 할 수 있습니까? –

    +0

    입력 목록은 읽기 전용으로 표시되어야하며 각 요소는 다른 요소와 독립적입니다. 그러니 걱정할 필요가 없습니다. –

    관련 문제