使用MATLAB进行DJing(低电平I/O)

使用MATLAB进行DJing(低电平I/O),matlab,loops,file-io,text-files,cell-array,Matlab,Loops,File Io,Text Files,Cell Array,好了,各位,这是一周中我学习如何用MATLAB做奇怪事情的时间。这周是DJing。我需要做的是找出如何使我的函数输出长度最接近剩余时间的歌曲的名称。例如,如果我在炫耀我的DJ技能,我还有3:22的时间,我必须选择一首长度最接近剩余时间的歌曲(可以更短或更长)。我有一个.txt文件可供选择 Test Case song1 = pickSong('Funeral.txt', '3:13') song1 => 'Neighborhood #2 (Laika)' The file for th

好了,各位,这是一周中我学习如何用MATLAB做奇怪事情的时间。这周是DJing。我需要做的是找出如何使我的函数输出长度最接近剩余时间的歌曲的名称。例如,如果我在炫耀我的DJ技能,我还有3:22的时间,我必须选择一首长度最接近剩余时间的歌曲(可以更短或更长)。我有一个.txt文件可供选择

Test Case
song1 = pickSong('Funeral.txt', '3:13')
song1 => 'Neighborhood #2 (Laika)'


The file for this looks like:
1. Neighborhood #1 (Tunnels) - 4:48
2. Neighborhood #2 (Laika) - 3:33
3. Une annee sans lumiere - 3:40
4. Neighborhood #3 (Power Out) - 5:12
5. Neighborhood #4 (7 Kettles) - 4:49
6. Crown of Love - 4:42
7. Wake Up - 5:39
8. Haiti - 4:07
9. Rebellion (Lies) - 5:10
10. In the Backseat - 6:21
我已经计划好了,我的问题是填充我的细胞阵列。它只输入最后一首歌,然后在循环运行后将其更改为a-1。我试过三种不同的方法,最后一种是最复杂的(而且看起来很糟糕)。一旦我将单元格数组设置为正确的形式(作为完整的歌曲列表,而不仅仅是-1),我就应该清楚了

function[song] = pickSong(file_name,time_remain)

Song_list = fopen(file_name, 'r'); %// Opens the file
Song_names = fgetl(Song_list); %// Retrieves the lines, or song names here
Songs_in = ''; %// I had this as a cell array first, but tried to populate a string this time
while ischar(Songs) %// My while loop to pull out the song names
Songs_in = {Songs_in, Songs}; 
Songs = fgetl(Song_list);
if ischar(Songs_in) %//How I was trying to populate my string
    song_info = [];
    while ~isempty(Songs_in)
    [name, time] = strtok(Songs_in);
    song_info = [song_info {name}]; 
        end
    end
end

[songs, rest] = strtok(Songs, '-');
[minutes, seconds] = strtok(songs, ':');
[minutes2, seconds2] = strtok(time_remain, ':')

all_seconds = (minutes*60) + seconds; %// Converting the total time into seconds
all_seconds2 = (minutes2*60) + seconds2;
song_times = all_seconds;
time_remain = all_seconds2

time_remain = min(time_remain - song_times);



fclose(file_name);

end
请并感谢您的帮助:)

一个棘手的案例:

song3 = pickSong('Resistance.txt', '3:57') 
song3 => 'Exogenesis: Symphony Part 2 (Cross-Pollination)'

1. Uprising - 5:02
2. Resistance - 5:46
3. Undisclosed Desires - 3:56
4. United States of Eurasia (+Collateral Damage) - 5:47
5. Guiding Light - 4:13
6. Unnatural Selection - 6:54
7. MK ULTRA - 4:06
8. I Belong to You (+Mon Coeur S'ouvre a Ta Voix) - 5:38
9. Exogenesis: Symphony Part 1 (Overture) - 4:18
10. Exogenesis: Symphony Part 2 (Cross-Pollination) - 3:57
11. Exogenesis: Symphony Part 3 (Redemption) - 4:37

您可以使用
textscan
进行管理,如下所示:

function[song,len] = pickSong(file_name,time_remain)

fid = fopen(filename);

toks = textscan(fid,'%[^-] - %d:%d');
songs = toks{1};
song_len = double(toks{2}*60 + toks{3});

[min_rem, sec_rem] = strtok(time_remain, ':');
time_rem = str2double(min_rem)*60 + str2double(sec_rem(2:end));

[len,i] = min(abs(time_rem - song_len));
song = songs{i};
请注意,只有当您的歌曲名称中没有'-'字符时,这才有效

编辑:这里有一个对任何歌曲标题都有效的解决方案:

function[song,len] = pickSong(file_name,time_remain)

file = fileread(file_name);
toks = regexp(file,'\d+. (.*?) - (\d+):(\d+)\n','tokens');
songs = cell(1,length(toks));
song_lens = zeros(1,length(toks));
for i=1:length(toks)
    songs{i} = toks{i}{1};
    song_lens(i) = str2double(toks{i}{2})*60 + str2double(toks{i}{3});
end

[min_rem, sec_rem] = strtok(time_remain, ':');
time_rem = str2double(min_rem)*60 + str2double(sec_rem(2:end));

[len,i] = min(abs(time_rem - song_lens));
song = songs{i};
regexp
是一个在字符串上运行正则表达式的MATLAB函数(在本例中为歌曲名称文件)。字符串
'\d+。(.*)-(\d+):(\d+)\n'
扫描每一行,提取每首歌曲的名称和长度
\d+
匹配一个或多个数字,而
*?
匹配任何数字。括号用于对输出进行分组。因此,我们有:

match n digits, followed by a (string), followed by (n-digits):(n-digits)

括号中的所有内容都作为单元格数组返回给
toks
变量。for循环只是从结果单元格数组中提取歌曲名称和长度。

您可以使用
textscan
进行管理,如下所示:

function[song,len] = pickSong(file_name,time_remain)

fid = fopen(filename);

toks = textscan(fid,'%[^-] - %d:%d');
songs = toks{1};
song_len = double(toks{2}*60 + toks{3});

[min_rem, sec_rem] = strtok(time_remain, ':');
time_rem = str2double(min_rem)*60 + str2double(sec_rem(2:end));

[len,i] = min(abs(time_rem - song_len));
song = songs{i};
请注意,只有当您的歌曲名称中没有'-'字符时,这才有效

编辑:这里有一个对任何歌曲标题都有效的解决方案:

function[song,len] = pickSong(file_name,time_remain)

file = fileread(file_name);
toks = regexp(file,'\d+. (.*?) - (\d+):(\d+)\n','tokens');
songs = cell(1,length(toks));
song_lens = zeros(1,length(toks));
for i=1:length(toks)
    songs{i} = toks{i}{1};
    song_lens(i) = str2double(toks{i}{2})*60 + str2double(toks{i}{3});
end

[min_rem, sec_rem] = strtok(time_remain, ':');
time_rem = str2double(min_rem)*60 + str2double(sec_rem(2:end));

[len,i] = min(abs(time_rem - song_lens));
song = songs{i};
regexp
是一个在字符串上运行正则表达式的MATLAB函数(在本例中为歌曲名称文件)。字符串
'\d+。(.*)-(\d+):(\d+)\n'
扫描每一行,提取每首歌曲的名称和长度
\d+
匹配一个或多个数字,而
*?
匹配任何数字。括号用于对输出进行分组。因此,我们有:

match n digits, followed by a (string), followed by (n-digits):(n-digits)

括号中的所有内容都作为单元格数组返回给
toks
变量。for循环只是从结果单元格数组中提取歌曲名称和长度。

我将使用您已经编写的大部分内容编写答案,而不是建议完全不同的内容。虽然
regexp
也是一个功能强大的函数(我喜欢正则表达式),但我发现它对于您目前所学的内容来说太高级了,所以现在让我们放弃它

通过这种方式,您可以了解代码的错误,以及我是多么棒的调试器(只是开玩笑)。当你在文本文件中阅读时,你所拥有的几乎是有效的。您在创建存储所有字符串的单元格数组时做了一个很好的选择

我还将借用MrAzzaman的逻辑,通过strtok计算以秒为单位的时间(顺便说一句,非常棒的工作)


另外,我要稍微改变一下你的逻辑,这样我就可以理解我该怎么做了。以下是基本算法:

  • 打开文件,像在代码中一样读取第一行(歌曲)
  • 初始化包含文本文件中第一首歌曲的单元格数组
  • 在到达文本文件末尾之前,读入整行并将其添加到单元格数组中。您还注意到,只要您点击一个
    -1
    ,我们就没有更多的歌曲可读了,所以请打破循环
  • 现在我们有了一个单元数组中的歌曲,其中包括每首歌曲的曲目编号、歌曲和时间,我们将再创建两个单元数组。第一个将只存储歌曲的时间作为字符串,分钟和秒由
    分隔。下一个将只包含歌曲本身的名称。现在,我们检查从步骤#3创建的单元数组中的每个元素

    (a) 为了填充第一个单元格数组,我使用查找出现
    -
    字符的所有实例。一旦我找到了这些发生的位置,我就选择了
    -
    发生的最后一个位置。我用它来索引我们的歌曲字符串,跳过2个字符来跳过
    -
    字符和空格字符。我们提取从这一点到行尾的所有字符以提取我们的时间

    (b) 为了填充第二个单元格数组,我再次使用
    strfind
    ,但随后我计算出空格出现的位置,并选择第一个空格出现的位置的索引。这对应于歌曲编号和歌曲曲目之间的间隙。使用(a)中的索引结果,我通过将第一个空格的索引中的一个字符跳过到最后一个
    -
    字符之前的两个字符来提取歌曲标题,以成功获取歌曲。这是因为在
    -
    字符之前的歌曲标题的最后一个单词之间可能会有一个空格,因此我们希望删除该空格

  • 接下来,对于步骤4中计算的第一个单元格数组中的每个歌曲时间,我使用
    strtok
    ,就像您使用的那样,并通过
    拆分字符串。MrAzzaman也使用了这个,我将借用他的逻辑来计算每次所需的总秒数

  • 最后,我们计算出哪个时间最接近剩余时间。请注意,我们还需要将剩余时间转换为秒,就像我们在步骤5中所做的那样。正如MrAzzaman所说,您可以使用MATLAB中的函数,并使用第二次输出
    >> pickSong('Funeral.txt', '3:13')
    ans = 
        'Neighborhood #2 (Laika)'
    
    >> pickSong('Resistance.txt', '3:57')
    ans = 
        'Exogenesis: Symphony Part 2 (Cross-Pollination)'
    
    >> t = readSongsFile('Funeral.txt');
    >> t.Minutes = fix(t.Duration/60);       % add minutes column
    >> t.Seconds = rem(t.Duration,60);       % add seconds column
    
    >> sortrows(t, 'Duration', 'descend')    % show table sorted by duration
    ans = 
        ID                Title                Duration    Minutes    Seconds
        __    _____________________________    ________    _______    _______
        10    'In the Backseat'                381         6          21     
         7    'Wake Up'                        339         5          39     
         4    'Neighborhood #3 (Power Out)'    312         5          12     
         9    'Rebellion (Lies)'               310         5          10     
         5    'Neighborhood #4 (7 Kettles)'    289         4          49     
         1    'Neighborhood #1 (Tunnels)'      288         4          48     
         6    'Crown of Love'                  282         4          42     
         8    'Haiti'                          247         4           7     
         3    'Une annee sans lumiere'         220         3          40     
         2    'Neighborhood #2 (Laika)'        213         3          33    
    
    % find songs that are at least 5 minutes long
    >> t(t.Minutes >= 5,:)
    
    % songs with the word "Neighborhood" in the title
    >> t(~cellfun(@isempty, strfind(t.Title, 'Neighborhood')),:)