Nadhas
Nadhas

Reputation: 5797

Ramda — Update elements of an array if they match elements from another array

I have two array of JSON objects

const array_one = [
  {id:'a',city:'Sydney',offer:'HAS'},
  {id:'b',city:'Sydney',offer:'AHR'},
  {id:'c',city:'Perth',offer:'AHR'},
];

const array_two = [
  {id:'a',html:''},
  {id:'b',html:''},
  {id:'c',html:''},
  {id:'d',html:''},
  {id:'e',html:''},
];

Update the array_two, add new property "isEligible" = true/false, based on array_one condition (where city = 'Sydney' and offer = 'AHR')

const array_two = [
      {id:'a',html:'', isEligible: false},
      {id:'b',html:'', isEligible: true},
      {id:'c',html:'', isEligible: false},
      {id:'d',html:'', isEligible: false}, // default false
      {id:'e',html:'', isEligible: false},
    ];

Tried the below:

array_two.forEach(arrayTwoItem=> {
    let arrayOneItem= R.find(
      R.propEq('id', arrayTwoItem.id)),
      array_one,
    );
    // eslint-disable-next-line no-param-reassign
    arrayTwoItem.isElibible= R.allPass[
    R.equals(
      'Sydney',
      arrayOneItem.city,
    ),
    R.equals(
      'AMR',
      arrayOneItem.offer,
    )]
 });

How to avoid the lint error , param reassign? how to completely solve using ramda?

tried R.assocPath, not worked.

Upvotes: 0

Views: 102

Answers (2)

customcommander
customcommander

Reputation: 18891

I'd write a function that takes a predicate and the array to update:

const eligibility =
  (city, offer, xs) => id =>
    any(whereEq({id, city, offer}), xs);

const up =
  pred => map(o =>
    ({...o, isEligible: pred(o.id)}));


console.log(

  up(eligibility('Sydney', 'AHR', array_one))(array_two)
  
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script>const {map, any, whereEq} = R;</script>
<script>
const array_one =
  [ {id:'a', city:'Sydney', offer:'HAS'}
  , {id:'b', city:'Sydney', offer:'AHR'}
  , {id:'c', city:'Perth' , offer:'AHR'}];

const array_two =
  [ {id:'a', html:''}
  , {id:'b', html:''}
  , {id:'c', html:''}
  , {id:'d', html:''}
  , {id:'e', html:''}];
</script>

Upvotes: 1

Scott Sauyet
Scott Sauyet

Reputation: 50787

One approach would be to write a function that looks like (city, offer) => (array_one) => (array_two) => updated version of array_two, one which you later can configure with "Sydney" and "AHR". It might look like this:

const matchId = pipe (eqProps ('id'), find) 

const update = (city, offer) => pipe (
  (xs) => (y, m = matchId (y) (xs)) => 
    assoc ('isEligible', Boolean (m) && m .city == city && m .offer == offer) (y),
  map
)

const array_one = [{id: 'a', city: 'Sydney', offer: 'HAS'}, {id: 'b', city: 'Sydney', offer: 'AHR'}, {id: 'c', city: 'Perth', offer: 'AHR'}]
const array_two = [{id: 'a', html: ''}, {id: 'b', html: ''}, {id: 'c', html: ''}, {id: 'd', html: ''}, {id: 'e', html: ''}]


console .log (update ('Sydney', 'AHR') (array_one) (array_two))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script>
<script> const {pipe, eqProps, find, assoc, map} = R </script>

matchId is a simple helper, and could be in-lined, but I find it more readable like this. The main function creates a mapping function by passing array_one into (xs) => (y, m = ...) => ..., and then passes that mapping function into map, ready for array_two. The mapping function checks for a record in array_one that has a matching id, and then uses assoc ('isElgible', ...) to return a value with the new property.

I'm sure that if we tried, we could make that predicate used for isEligible point-free, but I think this reads well like this, and I wouldn't bother.

Upvotes: 1

Related Questions