Tôi muốn viết một thuật toán shuffle đỉnh cuối cùng để sắp xếp bộ sưu tập mp3 của tôi


33

Tôi đang tìm kiếm các đề xuất mã giả để sắp xếp các tệp mp3 của mình theo cách tránh sự lặp lại tiêu đề và nghệ sĩ . Tôi lắng nghe những kẻ lừa đảo - Frank Sinatra, Tony Bennett, Ella Fitzgerald v.v ... hát những tiêu chuẩn cũ. Mỗi nghệ sĩ ghi lại nhiều bài hát giống nhau - Fly Me To The Moon, The Way You Look Tonight, Stardust, v.v. Mục tiêu của tôi là sắp xếp các bài hát (hoặc đặt hàng danh sách phát) với khoảng cách tối đa giữa các nghệ sĩ và tên bài hát. Vì vậy, nếu tôi có 2000 bài hát và 20 bài hát của Ella, tôi chỉ muốn nghe cô ấy một lần trong mỗi 100 bài hát. Nếu 10 nghệ sĩ hát Fly Me To The Moon, tôi muốn nghe một lần trong mỗi 200 bài hát. Tất nhiên tôi muốn kết hợp hai yêu cầu này để tạo ra "shuffle cuối cùng" của mình.

Tôi biết đây là một câu hỏi khá rộng mở. Tôi chưa bắt đầu lập trình nó nên tôi chỉ tìm kiếm gợi ý về một cách tiếp cận tốt. Tôi thực sự có một số yêu cầu khác liên quan đến khoảng cách đều nhau các thuộc tính bài hát khác nhưng tôi sẽ không tham gia vào đó ở đây.


Là một điểm khởi đầu, tôi đang sửa đổi mã, tôi tìm thấy ở đây để thao tác các tệp mp3 và đọc các thẻ ID3.

Tôi đã viết một ứng dụng nhỏ thỏa mãn nhu cầu của mình bằng cách sử dụng câu trả lời của Parsifal bên dưới. Tôi cũng đã viết một câu hỏi tiếp theo ở đây . Cám ơn vì tất cả những phản hồi tốt đẹp!


3
Câu hỏi thú vị, vấn đề tuyệt vời, ai đó biết rõ thuật toán thực sự sẽ có câu trả lời tuyệt vời dựa trên các phương pháp chính thức cho bạn.
Jimmy Hoffa

Vì vậy, nếu 50% bộ sưu tập nhạc của bạn là của cùng một nghệ sĩ, bạn sẽ muốn nghe nghệ sĩ đó cứ sau 2 bài hát, bất kể có bao nhiêu nghệ sĩ khác ... Có thể không nhiều như 50%, nhưng bạn có được ý kiến. Có thể chỉ là ý kiến ​​của tôi, nhưng điều đó không giống như một "shuffle cuối cùng", trừ khi bạn có số lượng bài hát gần như nhau từ mọi nghệ sĩ. Mặt khác, nếu bạn chỉ có 1 bài hát của một nghệ sĩ, bạn không muốn nó chơi quá nhiều. Tìm kiếm sự cân bằng giữa 2 không nên khó khăn.
Dukeling

Tôi sẽ chỉ làm một cái gì đó giống như mã giả này: while (length(songs) > 0) { x := rand(); addElem(shuffle, songs[x]); remElem(songs, x); }nhưng bạn nói rằng bạn muốn có một "shuffle cuối cùng". Tôi không biết bạn thực sự muốn gì với điều đó, thậm chí đọc câu hỏi ...
Cole Johnson

bạn có thể tải lên danh sách bài hát của mình ở đâu đó không - tab tiêu đề và nghệ sĩ hoặc đường ống được tách biệt hoặc XML
tgkprog

Thật đáng yêu khi có (như một plugin hoặc cốt lõi) trong Banshee!
phw

Câu trả lời:


5

Bạn có muốn chạy chương trình của mình một lần và tạo danh sách phát hoặc chọn bài hát tiếp theo không?

Nếu sau này, thì câu trả lời là đơn giản:

  • Tạo một mảng chứa tất cả các bài hát của bạn, với nghệ sĩ và tiêu đề
  • Tạo một danh sách (ưu tiên danh sách được liên kết) để giữ các tiêu đề bài hát được phát gần đây. Danh sách này bắt đầu trống và mỗi lần bạn phát một bài hát, bạn sẽ thêm nó vào danh sách. Khi danh sách đạt kích thước "không lặp lại bài hát" mong muốn của bạn, hãy bỏ mục cũ nhất (đầu tiên).
  • Ditto cho một danh sách các nghệ sĩ.

Chọn một bài hát sau đó trở thành chuỗi các bước sau:

  1. Chọn ngẫu nhiên một bài hát từ mảng "tất cả các bài hát". Đây chỉ là một số ngẫu nhiên giữa 0 và kích thước của mảng.
  2. Xem bài hát đó đã có trong danh sách bài hát đã phát chưa. Nếu có, quay lại bước 1.
  3. Xem nếu nghệ sĩ đã có trong danh sách nghệ sĩ chơi. Nếu có, quay lại bước 1.
  4. Thêm nghệ sĩ bài hát / tiêu đề vào danh sách thích hợp, bỏ các mục cũ nếu cần.
  5. Chơi bài hát.

Có một vài vấn đề có thể xảy ra, nhưng chúng chỉ nên quan trọng nếu bạn làm việc này như bài tập về nhà chứ không phải là một dự án thực sự.

  • Như @Dukeling đã nói trong một bình luận, nếu bộ sưu tập của bạn bị mất cân bằng đáng kể so với một ca sĩ hoặc tên bài hát, bạn có thể rơi vào một vòng lặp mà bạn liên tục từ chối các bài hát. Trong thực tế, điều này sẽ không phải là một vấn đề. Giải pháp là bạn cần giảm kích thước của danh sách "đã thấy". Và việc thêm bộ đếm ở bước # 2 và # 3 có thể cho bạn biết nếu đó là sự cố (nếu bạn thấy 10 lỗi liên tiếp, hãy đưa ra cảnh báo và / hoặc giảm kích thước của danh sách).
  • Nếu bạn đang cố gắng tạo danh sách phát chứa tất cả các bài hát của mình chỉ được phát một lần, bạn sẽ cần xóa các bài hát khỏi mảng nguồn. Điều này cũng sẽ thay đổi cách bạn đối phó với quá nhiều thất bại "được chơi gần đây" (vì cuối cùng bạn có thể chỉ có một nghệ sĩ trong mảng nguồn của mình).
  • Nếu thẻ ID3 của bạn là bất cứ thứ gì giống như của tôi, chúng có chứa nhiều lỗi sai chính tả. "Công tước Ellington" có cần phải khác với "Công tước Elingten" không? Nếu có, sau đó xem xét sử dụng công cụ đối sánh Levenstein khi quét các danh sách "được phát gần đây".

Tôi sử dụng RockBox ( rockbox.org ). Đối với bất kỳ thư mục bài hát nào, nó có thể tạo danh sách phát động (cũng có thể được lưu và đánh dấu). Tôi dự định tiền tố mỗi tên bài hát 0001, 0002 sau đó phát chúng theo thứ tự đó.
Nhà phát

@DeveloperDan - quy trình tương tự hoạt động, nhưng như tôi lưu ý ở cuối, bạn sẽ có khả năng có các bài hát không phù hợp với quy tắc. Bạn có hai lựa chọn: điều chỉnh quy tắc và chạy lại hoặc (nếu không có nhiều) chèn các bài hát một cách ngẫu nhiên.
Parsifal

Tôi sẽ tạo một danh sách ở bước 1 và xóa khỏi nó trong 2 và 3. Điều đó khiến bạn không thể bị mắc kẹt trong một vòng lặp và nếu danh sách trở nên trống rỗng, bạn biết rằng bạn cần thay đổi quy tắc và quét lại. Cách mạnh mẽ hơn để làm điều đó.
Macke

13

Tôi đã làm một cái gì đó như thế này trước khi sử dụng một trình tạo (trong C #, một vòng lặp vô hạn yieldlà mỗi vòng lặp lặp). Mỗi lần lặp lại nhìn vào nhóm bài hát của nó (hoặc bất cứ điều gì) và ném ra những bài đã được phát gần đây (hoặc bất kỳ tiêu chí tiêu cực nào). Sau đó, bạn chọn một từ danh sách được lọc và cập nhật trạng thái của bạn. Khi trạng thái của bạn trôi đi (bạn chơi các bài hát không phải Sinatra), các tiêu chí bị phá vỡ và các bài hát bị loại trừ của bạn bắt đầu được đưa vào lại.

Tất nhiên có những trường hợp góc để giải quyết:

  • Điều gì xảy ra nếu bạn ném ra tất cả các bài hát? (thường chỉ chọn một cách ngẫu nhiên, hy vọng làm mất ổn định nhà nước)
  • Có nên ưu tiên một số tiêu chí? (thường là vậy, có lẽ bạn không muốn chơi Fly Me to the Moon trở lại và không muốn chơi Sinatra trở lại, nhưng nếu đó là tất cả những gì bạn có ...)
  • Điều gì xảy ra nếu bộ sưu tập các bài hát của bạn được cập nhật giữa trận? (thường dễ xử lý, nhưng đồng thời có thể có vấn đề tùy thuộc vào cách sử dụng)

11

Bỏ qua các ngoại lệ của câu hỏi của bạn mà Telastyn đưa ra, có vẻ như bạn có một biến thể về vấn đề ba lô . May mắn thay, đó là một thuật toán tài liệu khá tốt.

Từ Wikipedia

Cho một tập hợp các mục, mỗi mục có trọng số và giá trị, xác định số lượng của từng mục để đưa vào bộ sưu tập sao cho tổng trọng lượng nhỏ hơn hoặc bằng một giới hạn nhất định và tổng giá trị càng lớn càng tốt.

Có một số biến thể có khả năng liên quan được liệt kê trong bài viết đó cùng với một danh sách bổ sung các vấn đề về chiếc ba lô


Một biến thể của vấn đề ba lô là vấn đề ba lô đa mục tiêu. Các đàn kiến thuật toán được đề xuất như một phương tiện để giải quyết vấn đề đó. Cách tiếp cận đàn kiến ​​có thể là cách dễ nhất để bạn tránh các khía cạnh NP-cứng trong câu hỏi của bạn.

Tôi cũng có thể xem xét vấn đề của bạn như là một biến thể cực đoan của vấn đề nhân viên bán hàng du lịch . Mỗi thành phố đến thăm thực sự là một bài hát mà bạn muốn chơi, nhưng tôi không chắc bạn sẽ chỉ định khoảng thời gian giữa các nghệ sĩ như thế nào. Gợi ý này cũng liên quan đến / có thể được giải quyết bằng cách tiếp cận đàn kiến.


8

Tôi đang làm việc với giả định rằng đây là "đây là thư viện của tôi, chạy chương trình này và tạo một đơn đặt hàng để phát các bài hát."

Điều này đã không được thực hiện và tôi không chắc nó sẽ tạo ra sự xáo trộn tốt như thế nào. Có thể là tôi hơi quá khắt khe trong bộ lọc, điều này sẽ dẫn đến kết quả (tôi tin) theo thứ tự quy định cho phần còn lại được cung cấp một bộ bài hát ban đầu.

Một cái có ideal_gapbăm. Điều này được tính bằng mật độ của một bài hát với một thuộc tính nhất định (nghệ sĩ, album, tiêu đề). Nếu một người có 2000 bài hát và 20 bài trong số đó là của một nghệ sĩ tên Ella, thì ideal_gap{'artist'}{"ella"}đó sẽ là 100.

Có thông tin này người ta cũng có tối đa các giá trị lý tưởng_gap. Hãy gọi đây max_gap.

Xem xét: có ideal_gapgiá trị tối đa để ngăn bài hát mà chỉ có hai nghệ sĩ hát để ngăn bài hát kia không được phát 1000 bài sau đó, đồng thời tăng mạnh giá trị max_gap dẫn đến nhiều lần lặp lại "tắt, không bài hát, quay lại tắt, không có bài hát ".

Kiểm tra các bài hát max_gap cuối cùng được phát (bài này có thể được tạo từ lần chạy trước để nếu nó kết thúc với Frank Sinatra hát Fly Me To the Moon, lần chạy tiếp theo sẽ không bắt đầu với cùng một bài hát), một trong những bài hát sẽ bị loại bỏ thư viện dẫn đến một tập hợp các bài hát ứng cử viên. Một bài hát sẽ chỉ có trong các bài hát ứng cử viên nếu tất cả các khoảng trống của nó nhỏ hơn các ideal_gapthuộc tính đó.

Từ tập hợp các bài hát ứng cử viên, chọn ngẫu nhiên một bài.

Xem xét: tính trọng số của tập hợp sao cho các bài hát thuộc tính có khoảng cách tối đa cao hơn sẽ có trọng số hơn. Bằng cách này, người ta không có tất cả các bài hát khoảng cách tối đa lớn hơn chồng chất ở cuối danh sách phát.

Hãy xem xét: thay vì có tất cả ba thuộc tính lớn hơn khoảng cách lý tưởng, chỉ hai trong số ba thuộc tính. Điều này có thể có nghĩa là một cái gì đó có thể được phát sớm hơn lý tưởng lý tưởng, nhưng tăng kích thước của bộ bài hát ứng cử viên có nghĩa là "chọn một ngẫu nhiên" có nhiều tùy chọn hơn.

Nếu không có bài hát nào đáp ứng yêu cầu, hãy lùi lại max_gap1, và tất cả lý tưởng_gaps theo n/max_gapphần trăm trong đó nsố lần điều này đã được tắt. Theo cách này, nếu có max_gap100, và nó đã bị lùi 5 lần trong lần lặp này, một lý tưởng_gap 100 sẽ được điều chỉnh tạm thời thành 95 và một lý tưởng_gap là 20 sẽ được điều chỉnh tạm thời thành 19. Lặp lại việc tắt khoảng cách cho đến khi có ít nhất một bài hát ứng cử viên, và sau đó chọn nó như trên.

Xem xét: có kích thước bể tối thiểu. Điều này làm tăng thêm phương sai, nhưng có thể dẫn đến việc một bài hát được phát sớm hơn khoảng cách lý tưởng khi có một bài hát khác có thể được phát.


1

Đây là một công việc tối ưu hóa, và một trong khá phức tạp nếu bạn đang tìm kiếm các giải pháp tối ưu. May mắn thay tôi tin rằng đó là một trong những trường hợp đủ tốt để làm.

Điều đầu tiên cần làm là thiết lập một tiêu chí chất lượng toán học, đó là một công thức đưa ra một hoán vị của danh sách sẽ trả về một số duy nhất mô tả mức độ hoán vị đó tốt hay xấu.

Một gợi ý công thức đơn giản, mỗi tiêu chí mà bạn muốn tính đến phải được cân nhắc, đưa ra trọng số cao cho các tiêu chí quan trọng và trọng số thấp cho các tiêu chí có nhiều bài hát chia sẻ cùng một tài sản, để những bài hát đó không chiếm ưu thế :

For each song on the list
    For each other song on the list
        For each criteria
            If the two songs share that criteria
                Add to the quality value: square root( [criteria weight]/[distance between the two songs] )

Giá trị mà thủ tục này tạo ra càng thấp, hoán vị danh sách càng tốt.

Làm hoán vị

Bây giờ bạn có thể sử dụng công thức này cho math.stackexchange và nhờ họ nói cho bạn biết nó khó đến mức nào và thực tế không thể tìm ra giải pháp tối ưu cho bất cứ thứ gì ngoại trừ một số lượng bài hát tầm thường, hoặc bạn có thể ném những chiếc đồng hồ vào đó và nhận được giải pháp tốt.

Có nhiều cách để làm điều này, đây là một:

Start with a random permutation of the list.
Several million times do the following:
    Select two entries at random
    For each of those two entries calculate their contribution to the quality value
    Swap the positions of the two entries
    Calculate the contribution to the quality value of the two entries at their new position
    If the sum of the calculations in the new positions is greater than the sum in the old positions
        Swap back

Đây là một thuật toán hơi lãng phí, nhưng nó dễ thực hiện và có thể giải quyết nhiều tiêu chí như một mong muốn.

Tối ưu hóa

Có thể áp dụng tải các tinh chỉnh và tối ưu hóa khác nhau, dưới đây là một số:

Trong tính toán giá trị chất lượng, đừng bận tâm kiểm tra một bài hát đối với mọi bài hát khác trong danh sách, thay vào đó chỉ kiểm tra bài hát đó với hơn 100 bài hát gần nhất. Đối với các giá trị chung, tối ưu hóa tốc độ này thực tế không ảnh hưởng đến chất lượng của kết quả.

Đối với một giá trị hiếm của một tài sản nhất định, có thể hiệu quả hơn để theo dõi các phiên bản hiện có của giá trị đó hơn là tìm kiếm chúng.

Nếu bạn cảm thấy rằng điều quan trọng là các giá trị có ít trường hợp được đặt gần nhau, thay vì cách xa nhau, có lẽ cần phải tăng trọng số cho các giá trị cụ thể đó, nhưng không phải cho các giá trị khác của tiêu chí đó.

Hàm giả ngẫu nhiên chọn tất cả các cặp có thể có trong danh sách trong phân phối bằng nhau có thể có hiệu quả trên mỗi lượt chọn tốt hơn một chút so với chọn ngẫu nhiên bình thường.


Tôi tin rằng thuật toán của bạn là một dạng ủ mô phỏng có thể là một nơi để tìm cách hoàn thiện nó hơn nữa.

@MichaelT Không, ủ mô phỏng sử dụng "nhiệt độ", cho phép nó hồi quy về trạng thái thấp hơn trong một nỗ lực để tránh bị bắt ở mức tối đa cục bộ. Đây chỉ là một tìm kiếm cục bộ , nó có thể được sửa đổi thành mô phỏng, hoặc bất kỳ thuật toán tìm kiếm xác suất nào khác tương đối dễ dàng, nhưng tôi không nghĩ rằng cần nhiều điều đó. Về cơ bản, tất cả những gì các thuật toán khác làm khác là cố gắng tránh cực đại cục bộ, nhưng tôi không nghĩ bạn sẽ tìm thấy một cực đại cục bộ cho vấn đề này không phải là một giải pháp chấp nhận được.
aaaaaaaaaaaa

0

Thật thú vị khi những cách tiếp cận khác nhau mà mọi người thực hiện. Tôi sẽ làm như sau:

Dựa trên tất cả các bài hát được phát cho đến nay, cho mỗi người một điểm. Chơi bản nhạc có số điểm thấp nhất (hoặc, trong trường hợp có số điểm giống hệt nhau, một bản ngẫu nhiên phù hợp với số điểm thấp nhất). Nói lại.

Tất nhiên, một chút khó khăn là cho điểm. Đối với mỗi bản nhạc có thể bạn có thể phát tiếp theo, bạn sẽ phải trải qua từng bản nhạc (hoặc một số lượng giới hạn) bạn đã phát. Nếu bản nhạc [có thể tiếp theo] và bản nhạc [được phát gần đây] có điểm chung, bạn thêm vào điểm số, tùy thuộc vào mức độ chung của chúng, điểm chung của chúng và thời gian bản nhạc [được phát gần đây] là bao lâu chơi. Bạn có thể muốn "không có gì chung" là 0, vì vậy bạn có thể bắt đầu với tất cả các bản nhạc là 0.

Bạn có thể sẽ muốn thử nghiệm với một số danh sách phát thủ công để bắt đầu, để làm cho toán học đúng - bạn có muốn số lượng từ chung hoặc bình phương của số lượng từ chung hoặc căn bậc hai của số từ chung? Chạy toàn bộ danh sách phát của bạn, xem những danh sách nào nổi lên trên cùng là "điểm chung nhất" và điều chỉnh các yếu tố để có được sự cân bằng đúng đắn. Có thể bạn muốn đi theo từng chữ cái, vì vậy "Duke Ellington" có điểm cao khi so sánh với "Duke Elington", nhưng điểm số thậm chí còn cao hơn khi so sánh với "King Elle Duton" (nếu tôi không bị mất bất kỳ chữ nào :) . Bạn nên xem xét rất cẩn thận những lĩnh vực bạn muốn so sánh và nếu bạn muốn so sánh giữa các lĩnh vực. Bạn thậm chí có thể xem xét các bigram (cặp chữ cái; trong trường hợp Duke ellington, "Du", "

Lưu ý rằng, nếu bạn có nhiều nghệ sĩ cụ thể, nghệ sĩ đó có thể được ưu tiên bỏ qua - bạn có thể nghe một bản nhạc của một nghệ sĩ độc đáo 5 lần, trước khi bạn nghe tất cả 10 bài hát của Duke Ellington. Điều này có thể hoặc không thể là những gì bạn muốn. Bạn có thể tránh điều này bằng cách thiết lập một từ điển tất cả mọi thứ bạn phải so sánh, và tần suất chúng xảy ra, vì vậy nếu bạn có nhiều bản nhạc Duke Ellington, hai bản nhạc của Duke Ellington là "ít giống nhau" hơn hai bởi Billy Joe Bleach .

Nó thậm chí có thể có giá trị trước khi tính toán một bảng với mỗi sự kết hợp của hai cặp bài hát. Ngoài ra, khi xem xét bài hát nào sẽ phát tiếp theo, bạn chỉ cần nhớ bài hát hay nhất cho đến nay; nếu bài tiếp theo được xem xét có điểm kém hơn bài hát hay nhất từ ​​trước đến nay, bạn có thể bỏ qua bài tiếp theo.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.