ความแตกต่างระหว่าง flatmap และ switchmap ใน RxJava คืออะไร?


149

rxjava docคำนิยามของ switchmap ค่อนข้างคลุมเครือและจะเชื่อมโยงไปยังหน้าเดียวกันเป็น flatmap ความแตกต่างระหว่างผู้ประกอบการทั้งสองคืออะไร?


1
เกี่ยวกับมันเชื่อมโยงไปยังหน้าเดียวกับ flatmap มันเป็นเรื่องจริง แต่เลื่อนลงไปที่ส่วนข้อมูลเฉพาะภาษาและเปิดโอเปอเรเตอร์ที่น่าสนใจ ผมคิดว่านี้ควรจะทำโดยอัตโนมัติจาก TOC แต่ ... นอกจากนี้คุณสามารถเห็นภาพเดียวกันในJavadoc
Ruslan Stelmachenko

คำตอบ:


180

อ้างอิงจากเอกสาร ( http://reactivex.io/documentation/operators/flatmap.html )

switchMapเป็นเหมือนflatMap, แต่มันจะปล่อยเฉพาะรายการจากที่สังเกตใหม่จนกว่าเหตุการณ์ใหม่จะถูกปล่อยออกมาจากแหล่งที่มาที่สังเกตได้

แผนภาพหินอ่อนแสดงให้เห็นว่าดี สังเกตเห็นความแตกต่างในไดอะแกรม:

ในswitchMapการปล่อยดั้งเดิมครั้งที่สอง( หินอ่อนสีเขียว ) ไม่ปล่อยการปล่อยแมปที่สองของมัน( สี่เหลี่ยมจัตุรัสสีเขียว ) เนื่องจากการปล่อยดั้งเดิมที่สาม( หินอ่อนสีน้ำเงิน ) เริ่มขึ้นแล้วปล่อยการปล่อยแมปแรก( เพชรสีน้ำเงิน ) ในคำอื่น ๆ เพียง แต่เป็นครั้งแรกของทั้งสองแมปการปล่อยก๊าซสีเขียวเกิดขึ้น; ไม่มีช่องสี่เหลี่ยมสีเขียวถูกปล่อยออกมาเนื่องจากเพชรสีฟ้าทุบมัน

ในflatMapผลลัพธ์ที่แมปทั้งหมดจะถูกปล่อยออกมาแม้ว่าพวกเขาจะ "ค้าง" ในคำอื่น ๆทั้งสองครั้งแรกและสองของแมปการปล่อยก๊าซสีเขียวเกิดขึ้น - เป็นสี่เหลี่ยมสีเขียวจะได้รับการปล่อยออกมา (ถ้าพวกเขาใช้ฟังก์ชั่นแผนที่ที่สอดคล้องกันและเนื่องจากพวกเขาไม่ได้คุณจะเห็นสองเพชรสีเขียวแม้ว่ามันจะถูกปล่อยออกมาหลังจากที่แรกเพชรสีฟ้า)

switchMap ใน switchMap ถ้าสิ่งที่สังเกตได้เดิมปล่อยสิ่งใหม่การปล่อยก่อนหน้านี้จะไม่สร้างสิ่งที่แมปไว้อีกต่อไป  นี่เป็นวิธีที่มีประสิทธิภาพในการหลีกเลี่ยงผลลัพธ์เก่า

flatMap

ใน switchMap ถ้าสิ่งที่สังเกตได้เดิมปล่อยสิ่งใหม่การปล่อยก่อนหน้านี้จะไม่สร้างสิ่งที่แมปไว้อีกต่อไป  นี่เป็นวิธีที่มีประสิทธิภาพในการหลีกเลี่ยงผลลัพธ์เก่า


4
ขอบคุณแผนภาพมีประโยชน์มาก คุณรู้ตัวอย่างโลกแห่งความจริงที่จะใช้ switchMap หรือไม่?
Julian Go

1
@JulianGo มีตัวอย่างที่นี่: github.com/samuelgruetter/rx-playground/blob/master/...มันใช้แต่ที่เป็นเช่นเดียวกับ.map(func).switch .switchMap(func)
ซามูเอล Gruetter

2
เพียงในกรณีที่มีคนยังคงต้องเป็นตัวอย่างที่โลกแห่งความจริงของ switchMap เขาสามารถทำตามลิงค์นี้การเชื่อมโยงและมันจะเข้าใจเมื่อใช้ swicthMap แทน flatMap
hermannovich

2
ยกตัวอย่างเช่นในการใช้ SwitchMap จากเบนเลชโดยใช้ RxJs5 - ดูนาทีที่ 25-26 นี่ - youtube.com/watch?v=3LKMwkuK0ZE สำหรับฉัน flatmap ก็เป็นที่เข้าใจแล้ว ...
arcseldon

7
แผนภาพหินอ่อนแสดงให้เห็นว่าดีหรือไม่? อะไร? ฉันเดาว่าคุณอาจเข้าใจ switchmap อยู่แล้ว
Helzgate

166

ฉันเจอสิ่งนี้เมื่อใช้ "การค้นหาทันที" - เช่นเมื่อผู้ใช้พิมพ์ในกล่องข้อความและผลลัพธ์ปรากฏขึ้นแบบเรียลไทม์ด้วยการกดปุ่มแต่ละครั้ง การแก้ปัญหาน่าจะเป็น:

  1. มีหัวเรื่องเช่น PublishSubject of String
  2. ในกล่องข้อความเปลี่ยนการติดต่อกลับให้เรียกใช้. onNext (ข้อความ)
  3. ใช้ตัวกรอง. debounce เพื่อ จำกัด การสอบถามของเซิร์ฟเวอร์
  4. ใช้ .switchMap เพื่อดำเนินการค้นหาเซิร์ฟเวอร์ - รับข้อความค้นหาและส่งคืน Observable ของ SearchResponse
  5. ใช้. สมัครสมาชิกด้วยวิธีการที่ใช้ SearchResponse และอัปเดต UI

ด้วย flatMap ผลการค้นหาอาจค้างเนื่องจากคำตอบการค้นหาอาจกลับมาไม่เป็นระเบียบ ในการแก้ไขปัญหานี้ควรใช้ switchMap เนื่องจากจะทำให้มั่นใจได้ว่าสามารถสังเกตได้แบบเก่าไม่สามารถบอกรับสมาชิกได้เมื่อมีการสร้างใหม่

ดังนั้นโดยสรุป flatMap ควรใช้เมื่อผลลัพธ์ทั้งหมดมีความหมายโดยไม่คำนึงถึงช่วงเวลาและควรใช้ switchMap เมื่อผลลัพธ์จากสสารที่สังเกตได้เท่านั้น


คุณสามารถตรวจสอบตัวอย่างนี้ใน GitHub
Cabezas

95

การอภิปรายไม่ flatMap สมบูรณ์โดยไม่ต้องเปรียบเทียบความแตกต่างกับswitchMap, และconcatMapconcatMapEager

วิธีการเหล่านี้ทั้งหมดใช้การFunc1แปลงกระแสเป็นObservables ซึ่งถูกปล่อยออกมาแล้ว; ความแตกต่างคือเมื่อObservables ที่ส่งคืนถูกสมัครและยกเลิกการสมัครสมาชิกและหากและเมื่อใดและการปล่อยของObservables เหล่านั้นถูกปล่อยออกมาโดย____Mapผู้ประกอบการที่มีปัญหา

  • flatMapสมัครรับข้อมูลที่ปล่อยออกมาObservableให้มากที่สุด (เป็นหมายเลขที่ขึ้นอยู่กับแพลตฟอร์มเช่นจำนวนที่ต่ำกว่าบน Android) ใช้สิ่งนี้เมื่อคำสั่งซื้อไม่สำคัญและคุณต้องการการปล่อยโดยเร็ว
  • concatMapสมัครสมาชิกคนแรกObservableและคนเดียวสมัครสมาชิกต่อไปObservableเมื่อคนก่อนหน้าได้เสร็จสิ้น ใช้สิ่งนี้เมื่อคำสั่งซื้อมีความสำคัญและคุณต้องการประหยัดทรัพยากร ตัวอย่างที่สมบูรณ์แบบคือการชะลอการเรียกเครือข่ายโดยการตรวจสอบแคชก่อน โดยทั่วไปอาจตามด้วย.first()หรือ.takeFirst()เพื่อหลีกเลี่ยงการทำงานที่ไม่จำเป็น

    http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

  • concatMapEagerทำงานเหมือนกันมาก แต่สมัครสมาชิกให้มากที่สุดเท่าที่จะเป็นไปได้ (ขึ้นอยู่กับแพลตฟอร์ม) แต่จะส่งเสียงเมื่อObservableเสร็จสิ้นก่อนหน้านี้ สมบูรณ์แบบเมื่อคุณมีการประมวลผลแบบขนานจำนวนมากที่ต้องทำ แต่ (ต่างจาก flatMap) ที่คุณต้องการรักษาลำดับเดิม

  • switchMapจะสมัครรับข้อมูลล่าสุดที่Observableพบและยกเลิกการเป็นสมาชิกจากObservables ก่อนหน้านี้ทั้งหมด สิ่งนี้เหมาะสำหรับกรณีเช่นคำแนะนำการค้นหา: เมื่อผู้ใช้มีการเปลี่ยนแปลงคำค้นหาของพวกเขาคำขอเก่าจะไม่สนใจอีกต่อไปดังนั้นจึงยกเลิกการสมัครสมาชิกและจุดสิ้นสุด Api ที่ทำงานได้ดีจะยกเลิกคำขอเครือข่าย

หากคุณกลับมาObservableที่ไม่มีsubscribeOnเธรดอื่นวิธีการทั้งหมดข้างต้นอาจทำงานเหมือนกันมาก พฤติกรรมที่น่าสนใจและมีประโยชน์จะปรากฏขึ้นเมื่อคุณอนุญาตให้Observables ที่ซ้อนกันทำงานบนเธรดของตนเอง จากนั้นคุณจะได้รับจะได้รับประโยชน์มากจากการประมวลผลแบบขนานและชาญฉลาดยกเลิกหรือไม่สมัครจากObservables ที่ไม่สนใจคุณSubscribers

  • ambอาจเป็นที่สนใจ ด้วยจำนวนObservables ใด ๆมันจะปล่อยไอเท็มเดียวกันกับที่อันแรกObservableที่ปล่อยออกมา ซึ่งอาจมีประโยชน์เมื่อคุณมีหลายแหล่งที่สามารถ / ควรส่งคืนสิ่งเดียวกันและคุณต้องการประสิทธิภาพ เช่นการเรียงลำดับคุณอาจambจัดเรียงอย่างรวดเร็วด้วยการผสานการจัดเรียงและใช้สิ่งที่เร็วกว่า

1
If you are returning Observables that don't subscribeOn another thread, all of the above methods may behave much the same.- คำอธิบายทุกข้อที่switchMap vs flatMapฉันพบมาก่อนพลาดประเด็นสำคัญนี้ไปตอนนี้ทุกอย่างชัดเจนขึ้น ขอบคุณ.
Andy Res

55

switchMap ครั้งหนึ่งเรียกว่า flatMapLatestใน RxJS 4

มันเป็นเพียงแค่ผ่านเหตุการณ์ที่เกิดขึ้นจากObservable ล่าสุดและยกเลิกการเป็นสมาชิกจากก่อนหน้านี้


@EpicPandaForce แม้ว่ามันจะไม่สอดคล้องกับการรวมกันล่าสุดซึ่งจะปล่อยค่าล่าสุดเมื่อใดก็ตามที่แหล่งที่ปล่อยออกมาสังเกตได้ (ไม่ปล่อยครั้งเดียว)
Michael Fry

2
เหตุผลส่วนหนึ่งที่เรียกว่า switchMap เป็นเพราะคุณสามารถใช้โอเปอเรเตอร์นี้ได้ด้วยตัวเองโดยใช้ o.map (... ). switch () ถึงแม้ว่าฉันจะนึกภาพออกมาว่ามันเป็น mapSwitch ซึ่งดูเหมือนจะไม่ทำให้ลิ้นหลุดง่ายนัก
Niall Connaughton

7

แผนที่ FlatMap, ConcatMapและSwitchMapใช้ฟังก์ชั่นหรือปรับเปลี่ยนข้อมูลที่ปล่อยออกมาโดยสังเกต

  • แผนที่ปรับเปลี่ยนแต่ละรายการปล่อยออกมาจากแหล่งที่สังเกตและส่งเสียงรายการปรับเปลี่ยน

  • FlatMap, SwitchMapและConcatMapยังใช้ฟังก์ชั่นในแต่ละรายการที่ปล่อยออกมา แต่แทนที่จะส่งคืนรายการที่แก้ไขมันจะส่งคืน Observable เองซึ่งสามารถส่งข้อมูลได้อีกครั้ง

  • FlatMapและConcatMapทำงานเหมือนกันมาก พวกเขารวมรายการที่ปล่อยออกมาจากหลาย Observables และส่งกลับ Observable เดียว

  • ความแตกต่างระหว่างFlatMapและConcatMapคือลำดับที่ปล่อยไอเท็ม
  • FlatMapสามารถ interleave รายการในขณะที่เปล่งออกมาคือการสั่งซื้อรายการที่ปล่อยออกมาจะไม่รักษา
  • ConcatMapรักษาลำดับของรายการ แต่ข้อเสียเปรียบหลักของ ConcatMap ก็คือมันต้องรอให้ Observable แต่ละอันทำงานให้เสร็จสมบูรณ์
  • SwitchMapเป็นบิตที่แตกต่างจากFlatMapและConcatMap SwitchMapยกเลิกการสมัครสมาชิกจากแหล่งข้อมูลก่อนหน้า Observable เมื่อใดก็ตามที่รายการใหม่เริ่มเปล่งดังนั้นจะเปล่งรายการจาก Observable ปัจจุบัน

1

หากคุณกำลังมองหารหัสตัวอย่าง

/**
 * We switch from original item to a new observable just using switchMap.
 * It´s a way to replace the Observable instead just the item as map does
 * Emitted:Person{name='Pablo', age=0, sex='no_sex'}
 */
@Test
public void testSwitchMap() {
    Observable.just(new Person("Pablo", 34, "male"))
              .switchMap(person -> Observable.just(new Person("Pablo", 0, "no_sex")))
              .subscribe(System.out::println);

}

คุณสามารถดูตัวอย่างเพิ่มเติมได้ที่นี่https://github.com/politrons/reactive


4
แต่คุณพลาดคุณลักษณะสำคัญของ switchMap ที่แตกต่างจาก flatMap - เป็นเรื่องที่สังเกตได้ล่าสุดเท่านั้นในขณะที่ยกเลิกการสมัครจากรายการก่อนหน้า
Artem Novikov

3
ในตัวอย่างนี้เมื่อคุณแทนที่switchMapด้วยflatMapมันจะทำงานเหมือนกันทุกประการ
Piotr Wittchen

1

นี่คืออีกหนึ่ง - ยาว 101 เส้นตัวอย่างเช่น นั่นอธิบายสิ่งที่ฉัน

อย่างที่เคยถูกกล่าวไว้: มันจะเป็นสิ่งที่สังเกตได้ครั้งสุดท้าย (ช้าที่สุดถ้าคุณต้องการ) และละเว้นสิ่งที่เหลือ

ผลที่ตามมา:

Time | scheduler | state
----------------------------
0    | main      | Starting
84   | main      | Created
103  | main      | Subscribed
118  | Sched-C-0 | Going to emmit: A
119  | Sched-C-1 | Going to emmit: B
119  | Sched-C-0 | Sleep for 1 seconds for A
119  | Sched-C-1 | Sleep for 2 seconds for B
1123 | Sched-C-0 | Emitted (A) in 1000 milliseconds
2122 | Sched-C-1 | Emitted (B) in 2000 milliseconds
2128 | Sched-C-1 | Got B processed
2128 | Sched-C-1 | Completed

คุณเห็นตัว A ถูกเพิกเฉย

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