将播放列表轨道分配给 3D 阵列

Posted

技术标签:

【中文标题】将播放列表轨道分配给 3D 阵列【英文标题】:Assign Playlist-Tracks to 3D Array 【发布时间】:2017-06-30 04:28:02 【问题描述】:

所以我在使用 Spotify 的 API 进行实验时遇到了我遇到过的最复杂的问题。我有类型文本文件,例如“寒冷”或“房子”。在这些文件中,我有指向 Spotify 播放列表的链接。这些行中的第一行代表我的这种类型的播放列表,例如:

myplalyist-ID 
random1-ID 
random2-ID ...

现在,由于这些链接指向播放列表,因此这些播放列表包含曲目。现在我想从那些随机播放列表中获取所有曲目并将其放入我的(过滤和添加曲目不是这里的问题,只是为了让你了解)。 现在我想我可以创建一个 3D 数组来处理这些音轨,例如:

1D: genre1    - genre2    - genre3
2D: playlist1 - playlist2 - playlist3
3D: tracks1   - tracks2   - tracks3

我希望你明白我的意思,我希望能够通过这样的方式访问播放列表轨道:

foreach(PlaylistTrack track in array[genre][playlist])
    // filter & add "track"

所以我的处理方法如下:

//PlaylistTrack is the type in which Spotify stores a track within a Playlist
private List<PlaylistTrack>[,,] playlistTracks;//3D???
//this is to store the amount of playlists within a genre
private int[] playlistArray;
//int to save the amount of genre-files
private int fileCount;

//-----------------METHOD:

private void getTracks()

    DirectoryInfo dir = new DirectoryInfo(this.path);//directory where genres are stored

    this.fileCount = 0;

    foreach (var file in dir.GetFiles("*.txt"))
    
        if (file.Name != "My Tracks.txt" && file.Name != "Tracks.txt")//getting all genre textfiles
        
            this.fileCount++;
        
    

    this.playlistArray = new int[this.fileCount];

    //i know using the foreach over and over is kinda bad and not preofessional,
    //but i don't use c# on a daily base and i didn't knew how to get it done otherwise

    int count = 0;
    foreach (var file in dir.GetFiles("*.txt"))
    
        if (file.Name != "My Tracks.txt" && file.Name != "Tracks.txt")
        
            int count2 = 0;
            if (File.ReadAllText(file.FullName) != "")
            
                using (StreamReader sr = new StreamReader(file.FullName))
                
                    string line = "";
                    while ((line = sr.ReadLine()) != null)
                    
                        if (line != "")
                        
                            count2++;
                        
                    
                

            
            this.playlistArray[count] = count2;
            count++;
        
    

    for (int i = 0; i < this.fileCount; i++)
        this.playlistTracks[i] = new List<PlaylistTrack>[this.playlistArray[i]]();
    //here i'm stuck, how would i initialize the array, so it can holds a bunch of PlaylistTrack Items in "3rd row", 
    //accessable through [genre][playlist]

非常感谢任何帮助,因为我完全迷失了这个! :)

编辑: 这就是我尝试过的:

//Setting File-Count to 0
this.fileCount = 0;

//Init new Dictionary
var allTracks = new Dictionary<string, Dictionary<string, List<PlaylistTrack>>>();

//Getting Directory where Genre-Files are
DirectoryInfo dir = new DirectoryInfo(this.path);

int count = 0;
//Looping through files in this Directory #1
foreach (var file in dir.GetFiles("*.txt"))

    //Get only Genre-Files, not Track-Lists
    if (file.Name != "My Tracks.txt" && file.Name != "Tracks.txt")
    
        count++;
    


//Init new string Array that will hold the Links to my Playlist for every genre
this.playlistLinks = new string[count];

//Looping through files in this Directory #2
foreach (var file in dir.GetFiles("*.txt"))

    //Get only Genre-Files, not Track-Lists
    if(file.Name != "My Tracks.txt" && file.Name != "Tracks.txt")
    
        //If the Genre-File has content
        if (File.ReadAllText(file.FullName) != "")
        
            //Getting the Genre Name, by splitting the Genre-File-Name
            string name = file.Name.Split(new string[]  ".txt" , StringSplitOptions.None)[0];

            //Reading the Genre-File
            using (StreamReader sr = new StreamReader(file.FullName))
            
                string line = "";
                bool first = false;
                //If the new line has content
                while ((line = sr.ReadLine()) != null)
                
                    //If it's not the first line and the line is not ""
                    if (first && line != "")
                    
                        //Splitting line to get Data
                        //split[0] = PlaylistID; split[1] = OwnerID
                        string[] split = line.Split(new string[]  " // " , StringSplitOptions.None);
                        //Getting Playlist Tracks and storing them in the Dictionary
                        //HERE HAPPENS THE ERROR
                        allTracks[name][split[0]] = this.getPlaylistTracks(split[1], split[0]);

                        //Looping through the Playlist-Tracks within the Dictionary
                        foreach (PlaylistTrack tr in allTracks [name][split[0]])
                        
                            //If the Track is on Spotify's Servers
                            if (!tr.IsLocal)
                            
                                //Filtering (not important here -> does work)
                                if (tr.AddedAt > time)
                                
                                    //Creating a string that holds Track's info
                                    string write = tr.Track.Name + " // " + string.Join(",", tr.Track.Artists.Select(source => source.Name));
                                    //Filtering tracks that i haven't listened to, by checking if track exists in "My Tracks.txt"
                                    //(not important here -> does work)
                                    if (!this.foundTrack(write))
                                    
                                        //Adding collected Tracks to another List, sorted by Genre
                                        //So all filtered Tracks from all Playlists within a genre are stored in one list
                                        this.tracksToAdd[this.fileCount].Add(tr);
                                    
                                
                            
                        
                    
                    //If it's the first line where the line is not ""
                    if(!first && line != "")
                    
                        string[] split = line.Split(new string[]  " // " , StringSplitOptions.None);
                        //Getting the PlaylistID of my Playlist
                        this.playlistLinks[this.fileCount] = split[0];
                        first = true;
                    
                
            
        
        //Increasing on every new Genre-File
        this.fileCount++;
    

错误发生了,我在代码中标记了它。错误消息是:

“System.Collections.Generic.KeyNotFoundException”异常有 发生在 mscorlib.dll 中。附加信息:指定的键 字典中没有指定。

(大致翻译自德语)

【问题讨论】:

【参考方案1】:

由于每个播放列表可以包含不同数量的歌曲,因此您不需要固定大小的 3D 矩阵 ([,,,]),而是需要一个数组数组 ([][][])。您可以在this question 中阅读它们之间的区别。

话虽如此,您可以使用PlayListTrack[][][] 实现您想要的。 您可以拥有类似var allTracks = new PlayListTrack[amountOfGenres][][]; 的内容,然后将allTracks 的每一行初始化为PlayListTrack[][],其大小是与该行匹配的流派的播放列表数量。最后,您可以将每个播放列表初始化为 PlayListTrack[],其大小是给定播放列表的歌曲数量。

无论如何,我建议您查看Dictionary<TKey, TValue> 类,它允许您将唯一键(例如,流派的 Id)映射到值(例如,播放列表,可能是字典本身)。

然后,你可以有类似的东西:

// Lists of tracks, indexed by their genre id (first string) and
// their playlist id (second string)
var allTracks = new Dictionary<string, Dictionary<string, List<PlayListTrack>>>();

// Examples

// Getting a genre, which is a Dictionary<string, List<PlayListTrack>>
var allJazzPlayLists = allTracks["jazz"];

// Getting a list of songs, which is a List<PlayListTrack>
var songs = allTracks["hip-hop"]["west side"];

【讨论】:

谢谢,很好的回答!我想这就是我正在寻找的。我添加了我在 OP 中尝试过的代码:也许你可以看看它并告诉我为什么会发生这个错误以及我该如何解决它。 您的错误发生是因为allTracks[name][split[0]] 试图获取不存在的allTracks[name]。在该行之前,如果该嵌套字典不存在,您应该创建它:if(!allTracks.ContainsKey(name)) allTracks[name] = new Dictionary&lt;string, List&lt;PlayListTrack&gt;&gt;();。然后,您可以调用allTracks[name][split[0]] = this.getPlaylistTracks(split[1], split[0]);,假设您的getPlaylistTracks(string, string) 方法返回List&lt;PlayListTrack&gt;

以上是关于将播放列表轨道分配给 3D 阵列的主要内容,如果未能解决你的问题,请参考以下文章

如何将 3D Python 列表传递给 C++ 程序

类列表将多个值分配给字符串列表

将列表成员分配给另一个列表

在 Kdb 中,如何将每个符号列表分配给值列表

将列表元素分配给变量

如何将列表内列表的值分配给列表内另一个列表的值(python)?