อัลกอริทึมสำหรับ UI ที่แสดงแถบเลื่อนเปอร์เซ็นต์ X ซึ่งค่าที่เชื่อมโยงรวมอยู่เสมอ 100%


11

ระบบที่ฉันสร้างประกอบด้วยชุดของตัวเลื่อน UI (จำนวนแตกต่างกัน) แต่ละตัวมีระดับ 0-100 โดยตัวเลื่อนฉันหมายถึง UI ที่คุณจับองค์ประกอบและลากขึ้นและลงเช่นการควบคุมระดับเสียง พวกเขาเชื่อมต่อกันด้วยอัลกอริทึมที่ช่วยให้มั่นใจว่าพวกเขาจะรวม 100 เสมอดังนั้นเมื่อเลื่อนหนึ่งเลื่อนขึ้นอื่น ๆ ทั้งหมดเลื่อนลงในที่สุดถึงศูนย์ เมื่อคนหนึ่งถูกเลื่อนลงคนอื่น ๆ ก็จะขยับขึ้น ทุกครั้งที่ผลรวมจะต้องเป็น 100 ดังนั้นที่นี่เลื่อนมีค่าต่าง ๆ แต่พวกเขารวม 100%:

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

หากตัวเลื่อนแรกเลื่อนขึ้นจาก 40 เป็น 70 ตัวเลื่อนอื่น ๆ จะต้องเลื่อนลงตามค่า (เนื่องจากตัวเลื่อนถูกลาก) หมายเหตุสามสไลเดอร์เปลี่ยนจาก 20 เป็น 10 และหนึ่งอยู่ที่ศูนย์เนื่องจากไม่สามารถลดลงได้

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

แน่นอนว่าเมื่อตัวเลื่อนใด ๆ มาถึง 0 หรือ 100 มันก็ไม่สามารถเคลื่อนไหวได้อีกต่อไปซึ่งเป็นสิ่งที่หัวของฉันเริ่มเจ็บจริงๆ ดังนั้นหากตัวเลื่อนเลื่อนได้สูงกว่าตัวเลื่อนอื่นก็จะลดลง แต่เมื่อตัวเลื่อนใด ๆ ถึงศูนย์เฉพาะอันที่เหลือที่ยังไม่ถึงศูนย์ก็สามารถเลื่อนลงได้

ฉันถามสิ่งนี้เพราะคำถามนี้เฉพาะกับอัลกอริทึมที่ไม่ใช้งาน FWIW แพลตฟอร์มดังกล่าวเป็น Android Java แต่นั่นไม่เกี่ยวข้องโดยเฉพาะ

วิธีที่ฉันใช้กับการแทงครั้งแรกของฉันคือการคำนวณเปอร์เซ็นต์การเปลี่ยนแปลงของตัวเลื่อนที่เคลื่อนที่ จากนั้นฉันแบ่งการเปลี่ยนแปลงนั้นและนำไปใช้ (ในทิศทางอื่น) กับค่าตัวเลื่อนอื่น ๆ ปัญหาที่เกิดขึ้นคือการใช้เปอร์เซ็นต์และการคูณหากตัวเลื่อนใด ๆ มีค่าเป็นศูนย์จะไม่สามารถเพิ่มขึ้นได้อีกจากศูนย์ - ผลลัพธ์สุทธิจากการที่ตัวเลื่อนแต่ละตัวติดค้างที่ศูนย์ ฉันใช้แถบเลื่อนที่มีช่วง 0 - 1,000,000 เพื่อหลีกเลี่ยงปัญหาการปัดเศษและดูเหมือนจะเป็นประโยชน์ แต่ฉันยังไม่ได้สร้างอัลกอริทึมที่จัดการสถานการณ์ทั้งหมดได้ดี


2
มีการถามคำถามที่คล้ายกันในเว็บไซต์ UX แม้ว่า IMHO จะไม่ได้รับคำตอบในลักษณะที่น่าพึงพอใจเป็นพิเศษ ฉันอยากรู้ว่ามีคำตอบที่ดีหรือไม่ แม้ว่าจะซื่อสัตย์ฉันพบว่าการใช้แถบเลื่อนเชื่อมโยงกันทำให้เกิดปัญหามากกว่าผู้ใช้ - มันยากที่จะจบลงด้วยการแจกจ่ายที่คุณต้องการเนื่องจากคุณทำการเปลี่ยนแปลงค่าที่คุณป้อนไปแล้วในขณะที่คุณ ไป.
Daniel B

1
ข้อเสนอแนะอย่างหนึ่งคืออนุญาตให้ผู้ใช้สลับระหว่างสองโหมดโดยที่หนึ่งตัวเลื่อนจะถูกเชื่อมโยงถึงกันและอีกอันที่ไม่ใช่ (และสลับกลับไปที่ "โหมดสัมพัทธ์" จะทำให้การกระจายแบบปกติ) สิ่งนี้จะช่วยให้คุณสามารถพูดคุยเกี่ยวกับปัญหาบางอย่างได้ แต่เพิ่มความซับซ้อนให้กับ UI เพื่อให้ผู้ใช้พิมพ์ค่าได้ง่ายขึ้น
Daniel B

คุณถูกต้องแน่นอนว่ามันต้องเล่นซอในส่วนของผู้ใช้ แต่ในกรณีนี้มันเป็นรูปแบบของแอพสำรวจที่สไลเดอร์เป็นตัวแทนของปัญหาดังนั้นคำถามทั้งหมดเกี่ยวกับน้ำหนักสัมพัทธ์ของค่า
Ollie C

1
ผมเข้าใจ ... ปัญหาของฉันเป็นเพียงที่แสดงสิ่งที่ต้องการ 60/30/10 แยกจะต้องมีมากขึ้นกว่า 3 การกระทำเพราะเมื่อเล่นซอกับ 30/10 ส่วน 60 ช่วยให้ย้ายไปรอบ ๆ มันจะแย่ลงเรื่อย ๆ เมื่อมีรายการขนาดใหญ่ขึ้นและเหมาะสำหรับการป้อนข้อมูลที่คลุมเครือมากเท่านั้นเนื่องจากคุณจะไม่ได้รับหมายเลขที่คุณมีอยู่ในหัว
Daniel B

2
จากจุด UX ของคุณฉันขอแนะนำให้มีการแสดงคะแนนรวมเป็นจำนวนมากออกไปด้านข้างของตัวเลื่อน ในขณะที่คุณเลื่อนตัวเลื่อนขึ้นหนึ่งครั้งคะแนนรวมจะเพิ่มขึ้นเป็น "100" และปุ่ม "ถัดไป" ของคุณจะถูกปิดใช้งานจนกว่าผู้ใช้เลื่อนตัวเลื่อนอื่นลงเพื่อลดคะแนนรวม คุณจะไม่มีทางรู้ว่าตัวเลื่อน 4 ตัวใดที่ผู้ใช้ต้องการลดเมื่อเลื่อนตัวเลื่อนหนึ่งตัวขึ้นมาดังนั้นอย่าลองด้วยซ้ำ
เกรแฮม

คำตอบ:


10

อัลกอริทึมโลภ

เมื่อตัวเลื่อนเลื่อนขึ้น (ลง) คนอื่น ๆ ทั้งหมดต้องเลื่อนลง (ขึ้น) แต่ละอันมีที่ว่างที่สามารถเคลื่อนย้ายได้ (สำหรับลง - ตำแหน่งของพวกมันสำหรับ: 100 ตำแหน่ง)

ดังนั้นเมื่อตัวเลื่อนหนึ่งเลื่อนให้ใช้ตัวเลื่อนอื่น ๆ จัดเรียงพวกมันตามพื้นที่ที่พวกมันสามารถเคลื่อนที่ได้และทำซ้ำไปเรื่อย ๆ

ในการวนซ้ำแต่ละครั้งให้เลื่อนตัวเลื่อนไปในทิศทางที่ต้องการโดย (ผลรวมเพื่อเลื่อนไปทางซ้าย / ตัวเลื่อนที่เหลืออยู่ในคิว) หรือระยะทางที่มันสามารถเคลื่อนที่ได้

นี่เป็นเชิงเส้นในความซับซ้อน (เนื่องจากคุณสามารถใช้คิวที่เรียงลำดับเดียวกันซ้ำแล้วซ้ำอีกเมื่อจัดเรียงแล้ว)

ในสถานการณ์นี้ไม่มีตัวเลื่อนติดอยู่พยายามย้ายให้มากที่สุดเท่าที่จะทำได้ แต่ขึ้นอยู่กับส่วนแบ่งที่ยุติธรรมเท่านั้น

ย้ายถ่วงน้ำหนัก

วิธีการที่แตกต่างกันคือการถ่วงน้ำหนักการเคลื่อนไหวที่พวกเขาต้องทำ ฉันคิดว่านี่คือสิ่งที่คุณพยายามทำโดยตัดสินจาก "แถบเลื่อนติดที่ 0" IMHO นี่เป็นธรรมชาติมากขึ้นคุณเพียงแค่ต้องปรับแต่งเพิ่มเติม

การคาดเดาอีกครั้งฉันจะบอกว่าคุณพยายามถ่วงน้ำหนักการเคลื่อนไหวของสไลเดอร์ที่แตกต่างกันตามตำแหน่งของพวกเขา (ซึ่งจะเป็นการแปลปัญหาที่ติดอยู่ที่ 0 โดยตรง) อย่างไรก็ตามโปรดทราบว่าคุณสามารถดูตำแหน่งตัวเลื่อนจากทิศทางที่แตกต่างกัน - จากจุดเริ่มต้นหรือจากจุดสิ้นสุด หากคุณรับน้ำหนักตามตำแหน่งตั้งแต่เริ่มต้นเมื่อลดลงและตำแหน่งสิ้นสุดเมื่อเพิ่มขึ้นคุณควรหลีกเลี่ยงปัญหาของคุณ

นี่เป็นคำศัพท์ที่คล้ายกันในส่วนก่อนหน้านี้ - อย่าถ่วงน้ำหนักการเคลื่อนไหวเพื่อทำตามตำแหน่งของตัวเลื่อนและถ่วงน้ำหนักตามพื้นที่ที่เหลือไว้เพื่อเคลื่อนไปในทิศทางนั้น


1
ฉันดูลึกลงไปและปรากฎว่าสิ่งที่ "ติดอยู่" นั้นไม่ได้ติดอยู่ แต่มีค่าต่ำเช่นนี้การเปลี่ยนแปลงเปอร์เซ็นต์แทบไม่มีผลกระทบใด ๆ - จำนวนที่ตัวเลื่อนเลื่อนจะสัมพันธ์กับค่าของมัน ฉันสงสัยว่าข้อเสนอแนะของคุณที่จะใช้ค่าตรงข้ามอาจทำงานได้ค่อนข้างดีกว่าฉันเพียง แต่ต้องรักษามูลค่ารวมไว้ที่ 100 ขอบคุณสำหรับการฉีดความชัดเจน
Ollie C

1

วิธีที่ฉันใช้จะแตกต่างกันเล็กน้อยและเกี่ยวข้องกับการใช้การเป็นตัวแทนภายในที่แตกต่างกันของแต่ละตัวเลื่อน

  1. ตัวเลื่อนแต่ละตัวสามารถรับค่าใด ๆ ได้ตั้งแต่ 0..100 (X) ซึ่งใช้เป็นค่าน้ำหนักสำหรับตัวเลื่อนนั้น (ไม่ใช่%)

  2. เพิ่มค่าตัวเลื่อนทั้งหมดเพื่อให้ได้ตัวเลขรวม (T)

  3. เพื่อกำหนดค่าที่แสดงของตัวเลื่อนแต่ละตัวให้ใช้ ROUND (X * 100 / T)

  4. เมื่อตัวเลื่อนเลื่อนขึ้นหรือลงคุณจะเปลี่ยนค่าของตัวเลื่อนเดียวเท่านั้น น้ำหนักสำหรับตัวเลื่อนนั้นจะเพิ่มขึ้นหรือลดลงเมื่อเทียบกับตัวเลื่อนอื่นทั้งหมดและตัวคำนวณข้างต้นจะช่วยให้มั่นใจได้ว่าการเปลี่ยนแปลงตัวเลื่อนอื่น ๆ ทั้งหมดจะถูกกระจายอย่างสม่ำเสมอเท่าที่จะทำได้


นี่จะเป็นอินเทอร์เฟซที่ดีถ้าผู้ใช้ส่วนใหญ่กังวลเกี่ยวกับเศษส่วนที่แม่นยำมากขึ้นหรือน้อยลง อย่างไรก็ตามฉันไม่สามารถเห็นได้ว่านี่คือหน้าที่แตกต่างจากการทำสไลด์อื่น ๆ อย่างไรให้ได้สัดส่วนกับตำแหน่งของพวกเขา
Ord

1

ฉันคิดว่าคุณกำลังซับซ้อนเกินไปโดยพยายามปรับค่าปัจจุบันตามเปอร์เซ็นต์ของการเปลี่ยนแปลงของตัวเลื่อน 'ย้าย' ซึ่งจะให้เปอร์เซ็นต์ของเปอร์เซ็นต์ซึ่งเป็นการแนะนำข้อผิดพลาดในการปัดเศษ

เมื่อคุณรู้ว่าคุณมีมูลค่ารวมเพียงแค่ 100 ฉันจะเก็บสิ่งต่าง ๆ เป็นจำนวนเต็มและทำงานย้อนกลับจาก 100 เพื่อหลีกเลี่ยงความยุ่งเหยิงอย่างร้ายแรงเกี่ยวกับการปัดเศษ (ในตัวอย่างด้านล่างฉันจัดการการปัดเศษเป็นจำนวนเต็มทั้งหมดในตอนท้าย)

เทคนิคของฉันคือตั้งค่าตัวเลื่อนแบบง่าย ๆ 0-100 ลบค่า 'ใหม่' จาก 100 เพื่อหาจำนวนที่จะกระจายกระจายไประหว่างแถบเลื่อนอื่นตามน้ำหนักแล้วล้างข้อมูล)

นี่ไม่ใช่เท่าที่ฉันทราบรหัส Android ที่ถูกต้อง: 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 

สิ่งนี้ควรจัดการกับค่า 0 หรือ 100 ใด ๆ


0

สิ่งที่เกี่ยวกับวิธีการ Round Robin สร้างธุรกรรมที่มั่นใจได้ว่าการเพิ่มมูลค่าให้กับหนึ่งเลื่อนจะลดลงจากเพื่อน และในทางกลับกัน.

จากนั้นทุกครั้งที่การเปลี่ยนแปลงของตัวเลื่อนทำงานกับธุรกรรมด้วยตัวเลื่อนที่แตกต่างกัน หากแถบเลื่อนเพียร์เป็นศูนย์ให้ทำต่อในส่วนถัดไป


0

เพียงอธิบายอย่างละเอียดเกี่ยวกับคำตอบของ Greedy Algorithm ที่ @Ordous นี่คือรายละเอียดของขั้นตอน

  1. เลื่อนตัวเลื่อน
  2. บันทึกdifferenceAmountมันเคลื่อนเป็นnewValue - OLDVALUE (บวกหมายถึงค่าที่มันเคลื่อนขึ้นและเลื่อนอื่น ๆ ที่จำเป็นต้องย้ายลงและในทางกลับกัน)
  3. เรียงลำดับคนอื่น ๆในรายการจากระยะทางอย่างน้อยที่สุดไปจนถึงระยะทางเกือบทั้งหมดที่พวกเขาสามารถเคลื่อนที่ไปในทิศทางที่กำหนดโดยความแตกต่างจำนวนเงินเป็นบวกหรือลบ
  4. ตั้งค่าamountToMove = ส่วนต่างจำนวนเงินที่เหลือ / อื่น ๆ จำนวนเงิน
  5. ห่วงผ่านและย้ายเลื่อนแต่ละโดยทั้งจำนวนเงินที่มันสามารถย้ายหรือ amountToMove แล้วแต่จำนวนใดจะน้อยกว่า
  6. ลบจำนวนที่ตัวเลื่อนย้ายจากamountToMoveและหารด้วยOtherCount ใหม่ ที่เหลืออยู่
  7. เมื่อเสร็จแล้วคุณจะสามารถกระจายความแตกต่างระหว่างตัวเลื่อนอื่น ๆ ได้สำเร็จ

คำตอบที่ยอดเยี่ยมที่นี่ stackoverflow.com/a/44369773/4222929
Sean

-3

เทคนิคอย่างง่ายอย่างหนึ่งคือการคำนวณเปอร์เซ็นต์ของค่าตัวเลื่อนที่สัมพันธ์กับผลรวมของค่าตัวเลื่อนแล้วกำหนดค่าตัวเลื่อนใหม่ให้กับเปอร์เซ็นต์ที่คำนวณตามลำดับ วิธีนี้จะปรับค่าตัวเลื่อนเช่น

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

แม้ว่าจะมีข้อผิดพลาดในการปัดเศษ แต่สามารถจัดการได้ในกรณีที่เราต้องการค่าของตัวเลื่อนเพื่อรวมและรวมได้ถึง 100 เสมอ

ฉันมีการตั้งค่าซอที่จะแสดงให้เห็นถึงการใช้ angularjs กรุณาเยี่ยมชมตัวอย่าง


2
... ซึ่งเป็นคำตอบของเจฟฟรีย์ โปรดอ่านคำตอบอื่น ๆ ก่อนเพื่อป้องกันการซ้ำซ้อน
Jan Doggen
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.