使用 LINQ 将嵌套循环平展为一个列表



我现在正在用 TPL 类替换我的一个旧的并行化辅助类。当操作代码中发生错误时,我的旧代码已被证明非常不可靠,并且它似乎不是为我现在正在做的事情而构建的。

第一份工作清单很容易翻译成Parallel.ForEach。但是这里有一个嵌套和索引循环,我无法轻易解决。

int streamIndex = 0;
foreach (var playlist in selectedPlaylists)
{
    var localPlaylist = playlist;
    foreach (var streamFile in playlist.StreamFiles)
    {
        var localStreamFile = streamFile;
        var localStreamIndex = streamIndex++;
        // Action that uses localPlaylist, localStreamFile and localStreamIndex
        ...
        // Save each job's result to its assigned place in the list
        lock (streamsList)
        {
            streamsList[localStreamIndex] = ...;
        }
    }
}

局部变量用于正确的闭包支持,因为 foreach 迭代变量是共享的。

我在想类似的事情

selectedPlaylists.SelectMany(p => p.StreamFiles)

但随后我失去了每个 streamFile 来自何处的关联,以及应该具有确定性的索引,因为它用于对结果列表中的结果进行排序。有没有办法保持这些与 Linq 的关联,并在枚举列表时添加该计数器?也许像这样(编造的伪代码):

selectedPlaylists
    .SelectMany(p => new
    {
        Playlist = p,
        StreamFile = ~~each one of p.StreamFiles~~,
        Index = ~~Counter()~~
    })

我可以保留那些旧的嵌套 foreach 循环并将所有作业收集到一个列表中,然后使用 Parallel.Invoke,但这似乎比需要的要复杂得多。我想知道是否有一个简单的 Linq 功能我还不知道。

好吧,你可以做这样的事情...

//
Dictionary<int, object> streamsList = new Dictionary<int, object>();
// First create a composition that holds the playlist and the streamfile
selectedPlaylists.SelectMany(playList => playList.StreamFiles.Select(streamFile => new { PlayList = playList, StreamFile = streamFile }))
                 // thenfor all of theese add the respective index
                 .Select((composition, i) => new { StreamFile = composition.StreamFile, PlayList = composition.PlayList, LocalStreamIndex = i })
                 .AsParallel()
                 .WithCancellation(yourTokenGoesHere)
                 .WithDegreeOfParallelism(theDegreeGoesHere)
                 .ForAll(indexedComposition =>
                 {
                     object result =somefunc(indexedComposition.LocalStreamIndex, indexedComposition.PlayList, indexedComposition.StreamFile);;
                     lock(streamsList) // dont call the function insde the lock or the as parallel is useless.
                         streamsList[indexedComposition.LocalStreamIndex] = result;
                 });

要展平StreamFiles并保持与PlayList关联并为其编制索引,您可以使用以下查询:

int index = 0;
var query = selectedPlaylists
              .SelectMany(p => p.StreamFiles
                               .Select(s =>
                                          new {
                                                PlayList = p,
                                                Index = index++,
                                                StreamFile = s
                                              }));

相关内容

  • 没有找到相关文章

最新更新