Algoritma untuk UI yang menampilkan slider persentase X yang nilai tertautnya selalu berjumlah 100%


11

Sebuah sistem yang saya bangun mencakup satu set slider UI (jumlahnya bervariasi) masing-masing dengan skala 0-100. Dengan slider maksud saya adalah UI tempat Anda mengambil elemen dan menyeretnya ke atas dan ke bawah, seperti kontrol volume. Mereka terhubung oleh suatu algoritma yang memastikan mereka selalu berjumlah 100. Jadi ketika satu slider digerakkan ke atas, yang lainnya semua bergerak ke bawah, akhirnya ke nol. Ketika satu dipindahkan ke bawah, yang lain bergerak ke atas. Setiap saat total harus 100. Jadi di sini slider memiliki berbagai nilai, tetapi totalnya 100%:

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

Jika slider pertama kemudian bergerak naik dari 40 ke 70, yang lain harus memindahkan nilai ke bawah (karena slider diseret). Perhatikan tiga penggeser berubah dari 20 menjadi 10, dan satu tetap pada nol karena tidak bisa lebih rendah.

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

Tentu saja ketika slider mana pun mencapai 0 atau 100, itu tidak bisa bergerak lebih jauh, yang mana kepala saya benar-benar mulai sakit. Jadi jika slider bergerak lebih tinggi, yang lain bergerak lebih rendah, tetapi ketika salah satu dari mereka mencapai nol hanya yang tersisa yang belum mencapai nol dapat bergerak lebih rendah.

Saya menanyakan ini di sini karena pertanyaan ini khusus untuk algoritme, bukan implementasinya. FWIW platformnya adalah Android Java, tetapi itu tidak terlalu relevan.

Pendekatan yang saya ambil dengan tikaman pertama saya adalah menghitung perubahan persentase slider yang bergerak. Saya kemudian membagi perubahan itu dan menerapkannya (ke arah lain) ke nilai slider lainnya. Masalahnya adalah bahwa dengan menggunakan persentase dan mengalikan, jika bilah geser mencapai nol, itu tidak akan pernah dapat ditingkatkan lagi dari nol - hasil bersihnya adalah bahwa bilah geser individu terjebak pada nol. Saya telah menggunakan slider dengan kisaran 0 - 1.000.000 untuk menghindari masalah pembulatan dan itu tampaknya membantu, tetapi saya belum membuat algoritma yang menangani semua skenario dengan baik.


2
Pertanyaan serupa telah ditanyakan di situs UX, meskipun IMHO mereka belum dijawab dengan cara yang sangat memuaskan. Saya ingin tahu apakah ada solusi yang bagus. Walaupun jujur, saya menemukan bahwa memiliki slider yang dikaitkan satu sama lain menyebabkan lebih banyak masalah daripada nilainya bagi pengguna - menjadi sulit untuk berakhir dengan distribusi yang Anda inginkan, karena Anda terus mengubah nilai yang sudah dimasukkan saat Anda Pergilah.
Daniel B

1
Satu saran adalah untuk memungkinkan pengguna untuk beralih di antara dua mode, pada dasarnya satu di mana slider dihubungkan satu sama lain, dan satu di mana mereka tidak (dan beralih kembali ke "mode relatif" akan menormalkan kembali distribusi). Ini akan memungkinkan untuk melangkahi beberapa masalah yang Anda sebutkan, tetapi tambahkan begitu banyak kerumitan ke UI sehingga mungkin lebih mudah untuk membuat pengguna mengetikkan nilai.
Daniel B

Anda tentu benar karena membutuhkan banyak pengotak dari sisi pengguna, tetapi dalam hal ini adalah bentuk aplikasi survei di mana slider mewakili masalah, jadi pertanyaannya adalah SEMUA tentang bobot relatif dari nilai.
Ollie C

1
Saya mengerti ... masalah saya adalah bahwa mengekspresikan sesuatu seperti split 60/30/10 akan membutuhkan lebih dari 3 tindakan, karena ketika mengutak-atik bagian 30/10, 60 terus bergerak. Ini semakin memburuk dengan daftar yang lebih besar, dan hanya benar-benar cocok untuk input yang sangat samar, karena Anda tidak akan pernah sampai ke nomor yang ada di kepala Anda.
Daniel B

2
Dari sudut pandang UX Anda, saya sarankan agar skor total disajikan sebagai angka besar di samping bilah geser. Saat Anda menggeser satu penggeser ke atas, skor total meningkat lebih dari "100" dan apa pun tombol "berikutnya" Anda akan dinonaktifkan hingga pengguna menurunkan penggeser lain ke bawah untuk mengurangi skor total. Anda tidak akan pernah tahu mana dari 4 slider lain yang ingin dikurangi pengguna ketika mereka geser satu slider ke atas, jadi jangan coba-coba.
Graham

Jawaban:


10

Algoritma Serakah

Ketika slider bergerak ke atas (bawah), semua yang lain perlu bergerak ke bawah (ke atas). Masing-masing memiliki beberapa ruang yang dapat dipindahkan (untuk turun - posisi mereka, untuk naik: 100-posisi).

Jadi, ketika satu slider bergerak, ambil slider lainnya, urutkan berdasarkan ruang yang dapat mereka gerakkan, dan cukup geser melalui slider.

Pada setiap iterasi, gerakkan penggeser ke arah yang diperlukan oleh (total untuk menggerakkan kiri / penggeser ke kiri dalam antrian) atau jarak yang dapat digerakkan, mana yang lebih kecil.

Ini linear dalam kompleksitas (karena Anda dapat menggunakan antrian yang sama berulang kali, setelah dipilah).

Dalam skenario ini, tidak ada slider yang macet, semua mencoba bergerak sebanyak yang mereka bisa, tetapi hanya sampai bagian yang adil.

Langkah tertimbang

Pendekatan yang berbeda adalah dengan mempertimbangkan langkah yang harus mereka lakukan. Saya pikir ini adalah apa yang Anda coba lakukan, menilai dengan pernyataan "slider Anda terjebak pada 0". IMHO ini lebih alami, Anda hanya perlu melakukan lebih banyak tweaker.

Berspekulasi lagi, saya akan mengatakan Anda mencoba untuk menimbang pergerakan slider yang berbeda dengan posisi mereka (Ini akan langsung diterjemahkan ke macet Anda pada masalah 0). Namun perhatikan bahwa Anda dapat melihat posisi slider dari berbagai arah - dari awal atau dari akhir. Jika Anda menimbang berdasarkan posisi dari awal ketika menurun dan posisi dari ujung saat meningkat, Anda harus menghindari masalah Anda.

Ini sangat mirip dalam terminologi dengan bagian sebelumnya - jangan menimbang pergerakan yang dilakukan oleh posisi slider, timbang dengan ruang yang tersisa untuk bergerak ke arah itu.


1
Saya melihat lebih dalam dan ternyata yang "macet" tidak macet, tetapi hanya memiliki nilai rendah seperti perubahan persentase hampir tidak berpengaruh - jumlah slider bergerak relatif terhadap nilainya. Saya menduga saran Anda untuk menggunakan nilai sebaliknya mungkin bekerja lebih baik, saya hanya perlu menjaga nilai total 100. Terima kasih telah menyuntikkan beberapa kejelasan.
Ollie C

1

Pendekatan yang saya ambil sedikit berbeda, dan melibatkan penggunaan representasi internal yang berbeda dari setiap slider.

  1. setiap slider dapat mengambil nilai apa pun dari 0..100 (X) yang digunakan sebagai faktor bobot untuk slider itu (bukan%)

  2. tambahkan semua nilai slider untuk mendapatkan angka total (T)

  3. untuk menentukan nilai yang ditampilkan setiap slider, gunakan ROUND (X * 100 / T)

  4. ketika slider dipindahkan ke atas atau ke bawah, Anda hanya mengubah nilai slider satu ; bobot untuk slider itu akan meningkat atau berkurang relatif terhadap semua slider lainnya, dan calc di atas akan memastikan bahwa perubahan untuk semua slider lainnya akan menyebar selebar mungkin.


Ini akan menjadi antarmuka yang baik jika pengguna terutama khawatir tentang membuat pecahan lebih atau kurang tepat. Namun, saya tidak dapat melihat bagaimana ini secara fungsional berbeda dari membuat slide lain bergerak proporsional dengan posisi mereka.
Ordous

1

Saya pikir Anda terlalu menyulitkan hal-hal dengan mencoba menyesuaikan nilai saat ini dengan persentase dari perubahan slider 'pindah', yang memberi Anda persentase persentase, yang memperkenalkan kesalahan pembulatan.

Karena Anda tahu Anda hanya pernah berurusan dengan nilai total 100, saya akan menjaga hal-hal sebagai bilangan bulat dan bekerja mundur dari 100, menghindari masalah serius dengan pembulatan. (Pada contoh di bawah ini saya menangani pembulatan sebagai bilangan bulat keseluruhan pada akhirnya)

Teknik saya adalah mengatur slider sesederhana 0-100. Kurangi nilai 'baru' dari 100 untuk mengetahui berapa banyak yang harus didistribusikan, sebarkan di antara slider lainnya sesuai dengan beratnya, lalu bersihkan)

Sejauh ini saya tahu, ini bukan kode Android yang valid: 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 

Ini secara intrinsik harus menangani nilai 0 atau 100


0

Bagaimana dengan pendekatan Round Robin? Buat transaksi yang memastikan bahwa menambahkan nilai ke satu slider akan mengurangi dari rekannya. dan sebaliknya.

Kemudian setiap kali perubahan slider menjalankan transaksi dengan slider rekan yang berbeda (saya akan membuat iterator yang mengembalikan slider rekan secara bergantian). Jika slider rekan adalah nol maka lanjutkan ke yang berikutnya.


0

Hanya untuk menguraikan jawaban Algoritma Greedy yang hebat dari @Ordous. Berikut adalah rincian langkah-langkahnya.

  1. Pindahkan Penggeser
  2. Simpan perbedaanAmount itu dipindahkan sebagai newValue - oldValue (Nilai positif berarti itu naik dan bilah geser lain perlu bergerak turun dan sebaliknya)
  3. Urutkan yang lain dalam daftar dari paling sedikit ke sebagian besar jarak mereka BISA bergerak ke arah yang diperlukan oleh selisih. Positif atau negatif.
  4. Set the numberToMove = differenceAmount / sisanya, LainnyaCount
  5. Loop melalui dan bergerak setiap slider dengan baik jumlah itu dapat bergerak atau amountToMove . Mana yang lebih kecil
  6. Kurangi jumlah slider melakukan langkah dari amountToMove dan bagi dengan yang baru tersisa OthersCount
  7. Setelah selesai, Anda telah berhasil mendistribusikan selisih antara slider lainnya.

Jawaban yang fantastis di sini. stackoverflow.com/a/44369773/4222929
Sean

-3

Salah satu teknik sederhana adalah menghitung persentase nilai slider relatif terhadap jumlah nilai slider dan kemudian menetapkan kembali nilai slider ke masing-masing persentase yang dihitung. nilai slider cara ini akan disesuaikan misalnya

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

Meskipun memperkenalkan kesalahan bulat tetapi bisa ditangani jika kita membutuhkan nilai slider dengan tepat dan selalu berjumlah hingga 100.

Saya telah menyiapkan biola untuk menunjukkan ini menggunakan angularjs. Silakan kunjungi demo


2
... yang merupakan jawaban Jeffrey. Harap baca jawaban lain terlebih dahulu untuk mencegah duplikat.
Jan Doggen
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.