Thuật toán cho giao diện người dùng hiển thị thanh trượt phần trăm X có giá trị được liên kết luôn luôn là 100%


11

Một hệ thống tôi đang xây dựng bao gồm một bộ thanh trượt UI (số lượng khác nhau) mỗi bộ có tỷ lệ 0-100. Theo thanh trượt, tôi có nghĩa là một giao diện người dùng nơi bạn lấy một yếu tố và kéo nó lên và xuống, giống như điều khiển âm lượng. Chúng được kết nối bằng một thuật toán đảm bảo chúng luôn có tổng số 100. Vì vậy, khi một thanh trượt được di chuyển lên, tất cả các thanh trượt khác di chuyển xuống, cuối cùng về không. Khi một người được chuyển xuống, những người khác di chuyển lên. Tại mọi thời điểm, tổng số phải là 100. Vì vậy, ở đây thanh trượt có các giá trị khác nhau, nhưng chúng có tổng số 100%:

----O------ 40
O----------  0
--O-------- 20
--O-------- 20
--O-------- 20

Nếu thanh trượt đầu tiên sau đó di chuyển LÊN từ 40 đến 70, các thanh trượt khác phải di chuyển XUỐNG về giá trị (khi thanh trượt được kéo). Lưu ý ba thanh trượt thay đổi từ 20 thành 10 và một thanh trượt ở mức 0 vì nó không thể xuống thấp hơn.

-------O--- 70
O----------  0
-O--------- 10
-O--------- 10
-O--------- 10

Tất nhiên khi bất kỳ thanh trượt nào đạt 0 hoặc 100, nó không thể di chuyển thêm nữa, đó là lúc đầu tôi thực sự bắt đầu đau. Vì vậy, nếu một thanh trượt di chuyển cao hơn, những cái khác di chuyển thấp hơn, nhưng khi bất kỳ trong số chúng đạt đến 0, chỉ những thanh còn lại chưa đạt đến 0 mới có thể di chuyển thấp hơn.

Tôi đang hỏi điều này ở đây vì câu hỏi này dành riêng cho thuật toán chứ không phải việc thực hiện. FWIW nền tảng là Android Java, nhưng điều đó không đặc biệt liên quan.

Cách tiếp cận tôi đã thực hiện với cú đâm đầu tiên của mình là tính toán phần trăm thay đổi của thanh trượt đã di chuyển. Sau đó tôi tách sự thay đổi đó và áp dụng nó (theo hướng khác) cho các giá trị thanh trượt khác. Tuy nhiên, vấn đề là bằng cách sử dụng tỷ lệ phần trăm và nhân, nếu bất kỳ thanh trượt nào về 0, nó không bao giờ có thể tăng trở lại từ 0 - kết quả cuối cùng của điều đó là các thanh trượt riêng lẻ bị kẹt ở mức 0. Tôi đã sử dụng các thanh trượt với phạm vi từ 0 - 1.000.000 để tránh các vấn đề làm tròn và điều đó có vẻ hữu ích, nhưng tôi chưa tạo ra một thuật toán xử lý tốt tất cả các tình huống.


2
Các câu hỏi tương tự đã được hỏi trên trang web UX, mặc dù IMHO chúng chưa được trả lời theo cách đặc biệt thỏa mãn. Tôi tò mò muốn xem liệu có giải pháp tốt nào không. Mặc dù thành thật mà nói, tôi thấy rằng việc các thanh trượt được liên kết với nhau gây ra nhiều rắc rối hơn giá trị của nó ngay cả đối với người dùng - điều đó trở nên khó khăn với việc phân phối mà bạn thích, vì bạn cứ thay đổi các giá trị đã nhập của mình như bạn đi.
Daniel B

1
Một đề xuất là cho phép người dùng chuyển đổi giữa hai chế độ, về cơ bản là một trong đó các thanh trượt được liên kết với nhau và một nơi không (và chuyển trở lại "chế độ tương đối" sẽ bình thường hóa lại phân phối). Điều này sẽ cho phép đẩy mạnh một số vấn đề bạn đề cập, nhưng thêm rất nhiều sự phức tạp vào giao diện người dùng để người dùng có thể dễ dàng nhập các giá trị vào.
Daniel B

Bạn chắc chắn đúng, nó đòi hỏi rất nhiều vấn đề của người dùng, nhưng trong trường hợp này, đây là một dạng ứng dụng khảo sát trong đó các thanh trượt đại diện cho các vấn đề, vì vậy câu hỏi là TẤT CẢ về trọng số tương đối của các giá trị.
Ollie C

1
Tôi hiểu ... vấn đề của tôi chỉ là việc thể hiện một cái gì đó như chia 60/30/10 sẽ yêu cầu nhiều hơn 3 hành động, bởi vì khi đấu tranh với phần 30/10, 60 tiếp tục di chuyển. Nó dần dần trở nên tồi tệ hơn với các danh sách lớn hơn và chỉ thực sự phù hợp với đầu vào cực kỳ mơ hồ, vì bạn sẽ không bao giờ đạt được con số bạn có trong đầu.
Daniel B

2
Từ điểm UX của bạn, tôi khuyên bạn nên có tổng số điểm được trình bày dưới dạng một số lượng lớn bên cạnh các thanh trượt. Khi bạn trượt một thanh trượt lên, tổng số điểm tăng hơn "100" và bất cứ điều gì nút "tiếp theo" của bạn sẽ bị vô hiệu hóa cho đến khi người dùng trượt một thanh trượt khác xuống để giảm tổng điểm. Bạn sẽ không bao giờ biết được trong số 4 thanh trượt khác mà người dùng muốn giảm khi họ trượt một thanh trượt lên, vì vậy đừng thử.
Graham

Câu trả lời:


10

Thuật toán tham lam

Khi một thanh trượt di chuyển lên (xuống), tất cả những người khác cần di chuyển xuống (lên). Mỗi người có một số không gian nó có thể di chuyển (cho xuống - vị trí của họ, cho lên: 100 vị trí).

Vì vậy, khi một thanh trượt di chuyển, hãy lấy các thanh trượt khác, sắp xếp chúng theo không gian chúng có thể di chuyển và chỉ cần lặp qua chúng.

Trên mỗi lần lặp, di chuyển thanh trượt theo hướng cần thiết bằng cách (tổng số để di chuyển sang trái / thanh trượt bên trái trong hàng đợi) hoặc khoảng cách nó có thể di chuyển, tùy theo giá trị nào nhỏ hơn.

Đây là tuyến tính phức tạp (vì bạn có thể sử dụng lặp đi lặp lại hàng đợi theo thứ tự, một khi nó đã được sắp xếp).

Trong kịch bản này, không có thanh trượt nào bị mắc kẹt, tất cả đều cố gắng di chuyển nhiều nhất có thể, nhưng chỉ dựa trên chia sẻ công bằng của họ.

Di chuyển có trọng số

Một cách tiếp cận khác sẽ là cân trọng lượng di chuyển họ cần làm. Tôi nghĩ rằng đây là những gì bạn đã cố gắng thực hiện, đánh giá bằng tuyên bố "thanh trượt của bạn bị kẹt ở 0". IMHO này là tự nhiên hơn, bạn chỉ cần thực hiện nhiều điều chỉnh.

Suy đoán một lần nữa, tôi sẽ nói bạn cố gắng cân nhắc các bước di chuyển của các thanh trượt khác nhau theo vị trí của chúng (Điều này sẽ trực tiếp chuyển sang vấn đề bị mắc kẹt của bạn ở mức 0). Tuy nhiên lưu ý rằng bạn có thể xem vị trí thanh trượt từ các hướng khác nhau - từ đầu hoặc từ cuối. Nếu bạn cân theo vị trí từ đầu khi giảm và vị trí từ cuối khi tăng, bạn nên tránh vấn đề của mình.

Điều này khá giống với thuật ngữ của phần trước - không cân nhắc việc di chuyển để thực hiện theo vị trí của các thanh trượt, cân nó theo khoảng trống mà chúng còn lại để di chuyển theo hướng đó.


1
Tôi nhìn sâu hơn và hóa ra những cái "bị kẹt" không bị kẹt, nhưng đơn giản là có giá trị thấp như vậy, phần trăm thay đổi hầu như không có tác dụng - số lượng thanh trượt di chuyển so với giá trị của nó. Tôi nghi ngờ đề xuất của bạn sử dụng giá trị ngược lại có thể hoạt động tốt hơn, tôi chỉ cần giữ tổng giá trị ở mức 100. Cảm ơn bạn đã tiêm một số rõ ràng.
Ollie C

1

Cách tiếp cận tôi thực hiện hơi khác nhau và liên quan đến việc sử dụng một biểu diễn bên trong khác nhau của mỗi thanh trượt.

  1. mỗi thanh trượt có thể lấy bất kỳ giá trị nào từ 0..100 (X) được sử dụng làm hệ số trọng số cho thanh trượt đó (không phải là%)

  2. cộng tất cả các giá trị thanh trượt để có được tổng số (T)

  3. để xác định giá trị hiển thị của mỗi thanh trượt, sử dụng ROUND (X * 100 / T)

  4. khi một thanh trượt được di chuyển lên hoặc xuống, bạn chỉ thay đổi giá trị của một thanh trượt ; trọng số cho thanh trượt đó sẽ tăng hoặc giảm so với tất cả các thanh trượt khác, và calc trên sẽ đảm bảo rằng sự thay đổi đối với tất cả các thanh trượt khác sẽ được trải đều nhất có thể.


Đây sẽ là một giao diện tốt nếu người dùng chủ yếu quan tâm đến việc tạo ra các phân số chính xác hơn hoặc ít hơn. Tuy nhiên, tôi không thể thấy điều này có chức năng khác với việc làm cho các slide khác di chuyển tỷ lệ thuận với vị trí của chúng.
2014

1

Tôi nghĩ rằng bạn đang làm phức tạp mọi thứ bằng cách cố gắng điều chỉnh giá trị hiện tại theo tỷ lệ phần trăm thay đổi của thanh trượt 'đã di chuyển', cung cấp cho bạn tỷ lệ phần trăm, điều này gây ra lỗi làm tròn.

Vì bạn biết rằng bạn chỉ từng giao dịch với tổng giá trị là 100, nên tôi giữ mọi thứ là số nguyên và làm việc ngược từ 100, tránh mọi rắc rối nghiêm trọng về làm tròn. (Trong ví dụ dưới đây, tôi xử lý bất kỳ làm tròn nào dưới dạng toàn bộ số nguyên ở cuối)

Kỹ thuật của tôi sẽ là đặt các thanh trượt là 0-100 đơn giản. Trừ giá trị 'mới' từ 100 để tính ra mức phân phối lại, trải đều giữa các thanh trượt khác theo trọng lượng của chúng, sau đó dọn sạch)

Đây không phải là, theo như tôi biết, mã Android hợp lệ: p

// see how much is "left" to redistribute
amountToRedistribute = 100 - movedSlider.value

//What proportion of the original 100% was contained in the other sliders (for weighting)
allOtherSlidersTotalWeight = sum(other slider existing values)

//Approximately redistribute the amount we have left between the other sliders, adjusting for their existing weight
for each (otherSlider)
    otherSlider.value = floor(otherSlider.value/allOtherSlidersWeight * amountToRedistribute)
    amountRedistributed += otherSlider.value

//then clean up because the floor() above might leave one or two leftover... How much still hasn't been redistributed?
amountLeftToRedistribute -= amountRedistributed

//add it to a slider (you may want to be smarter and add in a check if the slider chosen is zero, or add it to the largest remaining slider, spread it over several sliders etc, I'll leave it fairly simple here)
otherSlider1.value += amountLeftToRedistribute 

Điều này thực chất sẽ xử lý bất kỳ giá trị 0 hoặc 100


0

Cách tiếp cận Round Robin thì sao? Tạo một giao dịch đảm bảo rằng việc thêm giá trị vào một thanh trượt sẽ giảm từ đồng đẳng của nó. và ngược lại.

Sau đó, mỗi khi thay đổi thanh trượt chạy giao dịch với một thanh trượt ngang hàng khác nhau (tôi sẽ tạo một trình vòng lặp trả lại thanh trượt ngang hàng lần lượt). Nếu thanh trượt ngang bằng 0 thì tiến hành tiếp theo.


0

Chỉ cần giải thích về câu trả lời Thuật toán Tham lam tuyệt vời từ @Ordous. Đây là một sự cố của các bước.

  1. Di chuyển thanh trượt
  2. Lưu sự khác biệtAount nó di chuyển như newValue - oldValue (Giá trị dương có nghĩa là nó di chuyển lên và các thanh trượt khác cần di chuyển xuống và ngược lại)
  3. Sắp xếp những người khác trong danh sách từ ít nhất đối với hầu hết các khoảng cách họ có thể di chuyển theo hướng yêu cầu của differenceAmount là tích cực hay tiêu cực.
  4. Đặt amountToMove = differenceAmount / còn lại OthersCount
  5. Vòng qua và di chuyển mỗi thanh trượt bằng một trong hai mức nó có thể di chuyển hoặc amountToMove . Cái nào nhỏ hơn
  6. Trừ số tiền thanh trượt đã di chuyển từ amountToMove và chia cho mới còn lại OthersCount
  7. Sau khi kết thúc, bạn đã phân phối thành công sự khác biệt giữa các thanh trượt khác.

Câu trả lời tuyệt vời ở đây. stackoverflow.com/a/44369773/4222929
Sean

-3

Một kỹ thuật đơn giản là tính toán tỷ lệ phần trăm của các giá trị thanh trượt so với tổng các giá trị thanh trượt và sau đó gán lại các giá trị thanh trượt cho tỷ lệ phần trăm được tính tương ứng. cách này giá trị thanh trượt sẽ được điều chỉnh, ví dụ

slider1.value = (slider1.value / sumOfSliderValues) * 100 ;
slider2.value = (slider2.value / sumOfSliderValues) * 100 ;
slider3.value = (slider3.value / sumOfSliderValues) * 100 ;

Mặc dù nó giới thiệu lỗi làm tròn nhưng nó có thể được xử lý trong trường hợp chúng ta cần các giá trị thanh trượt chính xác và luôn tổng hợp lên tới 100.

Tôi đã thiết lập một fiddle để chứng minh điều này bằng cách sử dụng angularjs. Vui lòng truy cập bản demo


2
... đó là câu trả lời của Jeffrey. Xin vui lòng đọc các câu trả lời khác đầu tiên để ngăn ngừa trùng lặp.
Jan Doggen 17/03/2015
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.