{"action":"created","issue":{"url":"https://api.github.com/repos/ReactiveX/RxJS/issues/103","labels_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/103/labels{/name}","comments_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/103/comments","events_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/103/events","html_url":"https://github.com/ReactiveX/RxJS/pull/103","id":95782447,"number":103,"title":"implement partition operator","user":{"login":"robwormald","id":534930,"avatar_url":"https://avatars.githubusercontent.com/u/534930?v=3","gravatar_id":"","url":"https://api.github.com/users/robwormald","html_url":"https://github.com/robwormald","followers_url":"https://api.github.com/users/robwormald/followers","following_url":"https://api.github.com/users/robwormald/following{/other_user}","gists_url":"https://api.github.com/users/robwormald/gists{/gist_id}","starred_url":"https://api.github.com/users/robwormald/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robwormald/subscriptions","organizations_url":"https://api.github.com/users/robwormald/orgs","repos_url":"https://api.github.com/users/robwormald/repos","events_url":"https://api.github.com/users/robwormald/events{/privacy}","received_events_url":"https://api.github.com/users/robwormald/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":4,"created_at":"2015-07-18T03:07:34Z","updated_at":"2015-07-20T03:24:04Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ReactiveX/RxJS/pulls/103","html_url":"https://github.com/ReactiveX/RxJS/pull/103","diff_url":"https://github.com/ReactiveX/RxJS/pull/103.diff","patch_url":"https://github.com/ReactiveX/RxJS/pull/103.patch"},"body":"Implements .partition operator because I have impulse control problems. Does not include dist/ changes per #94 "},"comment":{"url":"https://api.github.com/repos/ReactiveX/RxJS/issues/comments/122746184","html_url":"https://github.com/ReactiveX/RxJS/pull/103#issuecomment-122746184","issue_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/103","id":122746184,"user":{"login":"robwormald","id":534930,"avatar_url":"https://avatars.githubusercontent.com/u/534930?v=3","gravatar_id":"","url":"https://api.github.com/users/robwormald","html_url":"https://github.com/robwormald","followers_url":"https://api.github.com/users/robwormald/followers","following_url":"https://api.github.com/users/robwormald/following{/other_user}","gists_url":"https://api.github.com/users/robwormald/gists{/gist_id}","starred_url":"https://api.github.com/users/robwormald/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/robwormald/subscriptions","organizations_url":"https://api.github.com/users/robwormald/orgs","repos_url":"https://api.github.com/users/robwormald/repos","events_url":"https://api.github.com/users/robwormald/events{/privacy}","received_events_url":"https://api.github.com/users/robwormald/received_events","type":"User","site_admin":false},"created_at":"2015-07-20T03:24:04Z","updated_at":"2015-07-20T03:24:04Z","body":"I stumbled across partition when messing with angular2 and http for the first time doing a boring autocomplete type scenario:\r\n```js\r\nconst queryStream = someFormControl.valueChanges.toRx();\r\n// \"c\"\r\n// \"ca\"\r\n// \"cat\"\r\n```\r\npiped into an http service to make queries against youtube\r\n```js\r\nconst searchResults = \r\nqueryStream.map(search => `search?q=${inputString}`).flatMapLatest(searchYouTube);\r\n// [video, video]\r\n// [video, video, video]\r\n// [video, video, video, video]\r\n```\r\nwith ng2 i can bind an observable directly to the view (nice) to display those results\r\n```js\r\nthis.searchResults = \r\n  queryStream\r\n    .map(search => `search?q=${inputString}`)\r\n    .flatMapLatest(searchYouTube);\r\n```\r\n```html\r\n  <ul>\r\n    <li *ng-for=\"video of searchResults | async\">{{video.title}}</li>\r\n  </ul>\r\n```\r\ni wanted to then \"reset\" the search results (with an empty array) when somebody cleared the input:\r\n```js\r\nconst queryStream = someFormControl.valueChanges.toRx();\r\n// \"cat\" -> [video, video, video]\r\n// \"ca\" -> [video, video, video]\r\n// \"c\" -> [video, video, video]\r\n// \"\" -> ???\r\n```\r\nmy (incredibly noobish) first attempt i'm not even going to post here, but @robertpenner plugged in partition for me to end up with the following - this wouldn't be nearly as useful without es6 destructuring.\r\n```js\r\nconst queryStream = someFormControl.valueChanges.toRx();\r\n\r\n//partition\r\nconst [searchesToMake, emptyInputs] = queryStream.partition(query => (query.length));\r\n\r\n//\"parallel\" streams \r\n//turn empty strings into empty arrays\r\nconst emptySearchResults = emptyInputs.map(() => []);\r\n//turn search strings into query results\r\nconst youTubeSearchResults = searchesToMake.map(makeQueryUrl).flatMapLatest(searchYouTube);\r\n\r\n//join back together and bind to the view\r\nthis.searchResults = youTubeSearchResults.merge(emptySearchResults);\r\n// \"c\" -> [video, video, video]\r\n// \"ca\" -> [video, video, video]\r\n// \"c\" -> [video, video, video]\r\n// \"\" -> []\r\n```\r\nThe use case here is effectively \"forking/splitting\" the stream based on a condition - it feels to me like a stream based if/else statement, vs a groupBy which feels more like a switch or if/...if else/else statement. \r\n\r\nOther use cases I can think of (and this might be of interest to @jeffbcross re: ngHttp) \r\n\r\nI'm unabashedly a promise fan because of the clear resolve / reject partitioning - things either succeed or fail - they may fail for any number of reasons but that first \"fork\" is quite clear to me - now I'm getting all Reactive partition seems like a nice extension of that concept: \r\n```js\r\n//isValid with promises\r\nfunction checkStatus(response) {\r\n  if (response.status >= 200 && response.status < 300) {\r\n    return response\r\n  } else {\r\n    var error = new Error(response.statusText)\r\n    error.response = response\r\n    throw error\r\n  }\r\n}\r\nlet fetchResults = fetch('/someurl').then(checkStatus).then(res => res.json());\r\n\r\nfetchResults.then(doStuffWithSuccesses, doStuffWithErrors);\r\n```\r\nthe Rx version's mental model is better - its not so much an \"error\" (throw) as much as \"a result other than the expected one\":\r\n```js\r\nconst [validResponses, invalidResponses] = someHttpQueryStream.partition(res => (res.status >= 200 && response.status < 300));\r\n//use responseSuccess and responseError \"interceptors\" cleanly \r\nconst jsonStream = validResponses.map(parseSuccessResponse);\r\nconst errorStream = invalidResponses.map(parseErrorResponse);\r\nconst responseStream = jsonStream.merge(errorStream);\r\n```\r\nYou might use groupBy downstream from that for handling different sorts of errors, as there are many possible error codes:\r\n```js\r\nlet errorStream = invalidResponses.map(parseErrorResponse).groupBy(res => res.statusCode)\r\n```\r\n\r\nExample quoted in the Rx docs is modulo -\r\n```js\r\nconst numbers = [1, 2, 3, 4, 5]\r\nconst [evens, odds] = numbers.partition(x => x % 2 === 0);\r\n```\r\n\r\nWayyy above my head but I think what I'm trying to explain (poorly) is something along the lines of https://en.wikipedia.org/wiki/Equivalence_class - partition is a way to express \"is\" or \"is not\" - which is different than \"belongs to\". A series of shapes could be subdivided into \"squares\" and \"not squares\", which is different to \"squares\", \"triangles\" and \"hexagons\". There are two and only two sets in the first, and any number of possible sets in the latter. 90% of that article is greek to me though, so I dunno. \r\n\r\n@blesh I would be curious in either case to see the groupBy equivalent - I think part of your point is that in a groupBy scenario the 2nd (\"else\") observable would be dynamically created as needed? Unless I'm missing something though that would require you to do some sort of check downstream from the groupBy, or some sort of if/else statement? \r\n\r\nSee also the discussion where it got added to Rx : https://github.com/Reactive-Extensions/RxJS/issues/141 - the OP puts its much more succinctly than my mad rambling :\r\n\r\n\"it allows to switch between 2 (or in the case of groupBy, n) observables depending on condition, I want to conditionally notify 2 different observer depending on a condition.\" \r\n\r\nAssuming the code is valid I think it's worth the 3 lines, though I'd be quite happy to implement it myself if there's a nice way to plug it in from userland. If the ES7 fnBind operator gets in this sort of thing would go nicely in a standalone aggregator type lib, or whatever the solution is for doing it nicely (lift?) \r\n```js\r\nconst partition = (predicate, thisArg) => [this.filter(predicate), this.filter(x => !predicate.call(thisArg, x))];\r\nconst [successes, failures] = queryStream::partition(res => (res.status >= 200 && response.status < 300));\r\n```\r\nmy 3c. Plunker of the original use case, looks nasty because I'm having to plug it in in the middle of the logic. http://plnkr.co/edit/5FfPoA?p=preview\r\n\r\napologies on the wall of text. this stuff is fun :D "}}