簡體   English   中英

如何使用 Ramda 將組合的 function 應用於列表中的每個 object?

[英]How do I apply a composed function to each object in a list using Ramda?

我正在使用 RamdaJS 構建一個簡單的應用程序,該應用程序旨在獲取代表美國各州的對象列表,並且對於每個 state,它應該計算選舉人票的數量並將該值作為新屬性添加到每個 object,稱為electoralVotes票。 計算本身的基本要點(盡管可能不准確)是將總體除以600000 ,然后將該數字向下舍入,如果向下舍入的數字為0 ,則將其向上舍入1

為簡單起見, states數組僅包含 state 名稱和每個 state 的人口:

const states = [
  { state: 'Alabama', population: 4833722 },
  { state: 'Alaska', population: 735132 },
  { state: 'Arizona', population: 6626624 },
  // ... etc.
];

我創建了一個名為getElectoralVotesForState的 function,它是使用嵌套的組合級別創建的(使用另一個組合函數構建的組合 function)。 這個 function 取一個 state object,檢查它的population屬性,然后計算並返回相應的選舉人票數。

const R = require('ramda');

// This might not be factually accurate, but it's a ballpark anyway
const POP_PER_ELECTORAL_VOTE = 600000;

const populationLens = R.lensProp("population");

// Take a number (population) and calculate the number of electoral votes
// If the rounded-down calculation is 0, round it up to 1
const getElectoralVotes = R.pipe(
  R.divide(R.__, POP_PER_ELECTORAL_VOTE),
  Math.floor,
  R.when(R.equals(0), R.always(1))
);

// Take a state object and return the electoral votes
const getElectoralVotesForState = R.pipe(
  R.view(populationLens),
  getElectoralVotes
);

如果我想將單個 state 傳遞給getElectoralVotesForState function,它可以正常工作:

const alabama = { state: 'Alabama', population: 4833722 };
const alabamaElectoralVotes = getElectoralVotesForState(alabama); // Resolves to 8

雖然這似乎適用於單個 object,但我似乎無法將其應用於對象數組 我的猜測是解決方案可能看起來像這樣:

const statesWithElectoralVotes = R.map(
  R.assoc("electoralVotes", getElectoralVotesForState)
)(states);

確實為每個 state 添加了一個electoralVotes屬性,但它是一個 function 而不是解析值。 我確定這只是一件愚蠢的事情,我在這里弄錯了,但我無法弄清楚。

我錯過了什么?

要將 function 應用於項目數組,請使用R.map 由於您需要不需要R.assoc的值:

 const POP_PER_ELECTORAL_VOTE = 600000; const populationLens = R.lensProp("population"); const getElectoralVotes = R.pipe( R.divide(R.__, POP_PER_ELECTORAL_VOTE), Math.floor, R.when(R.equals(0), R.always(1)) ); const getElectoralVotesForState = R.pipe( R.view(populationLens), getElectoralVotes ); const mapStates = R.map(getElectoralVotesForState); const states = [{"state":"Alabama","population":4833722},{"state":"Alaska","population":735132},{"state":"Arizona","population":6626624}]; const result = mapStates(states); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

另外,這里的鏡頭有點多余,取人口的值使用R.prop 我還將用R.when替換R.max

 const POP_PER_ELECTORAL_VOTE = 600000; const getElectoralVotesForState = R.pipe( R.prop('population'), R.divide(R.__, POP_PER_ELECTORAL_VOTE), Math.floor, R.max(1) ); const mapStates = R.map(getElectoralVotesForState); const states = [{"state":"Alabama","population":4833722},{"state":"Alaska","population":735132},{"state":"Arizona","population":6626624}]; const result = mapStates(states); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

如果您想將屬性添加到每個 object,您可以將R.chainR.assoc結合使用:

 const POP_PER_ELECTORAL_VOTE = 600000; const getElectoralVotesForState = R.pipe( R.prop('population'), R.divide(R.__, POP_PER_ELECTORAL_VOTE), Math.floor, R.max(1) ); const mapStates = R.map( R.chain(R.assoc("electoralVotes"), getElectoralVotesForState) ); const states = [{"state":"Alabama","population":4833722},{"state":"Alaska","population":735132},{"state":"Arizona","population":6626624}]; const result = mapStates(states); console.log(result);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

我認為 Ori Drori 很好地回答了你的問題。 我沒有建議的改進。 但我想表明,編寫當前用於美國國會的分配方法Huntington-Hill Method並不難:

 // Huntington-Hill apportionment method const apportion = (total) => (pops) => huntingtonHill (total - pops.length, pops.map (pop => ({...pop, seats: 1}))) // method of equal proportions const huntingtonHill = (toFill, seats, state = nextSeat (seats)) => toFill <= 0? seats: huntingtonHill (toFill - 1, seats.map (s => s.state == state? {...s, seats: s.seats + 1}: s)) // find state to assign the next seat const nextSeat = (seats) => seats.map (({state, population, seats}) => [state, population * Math.sqrt(1 / (seats * (seats + 1)))]).sort (([_, a], [_1, b]) => b - a) [0] [0] // ideally, use a better max implementation that sort/head, but low priority // convert census data to expected object format const restructure = results => results.slice (1) // remove header.map (([population, state]) => ({state, population})) // make objects.filter (({state}) =>, ['District of Columbia'. 'Puerto Rico'].includes (state)) // remove non-states:sort (({state, s1}: {state? s2}) => s1 < s2: -1? s1 > s2: 1: 0) // alphabetize fetch ('https.//api.census?gov/data/2021/pep/population,get=POP_2021:NAME&for=state.*').then (res => res.json()).then (restructure).then (apportion (435)).then (console.log).catch (console .warn)
 .as-console-wrapper {max-height: 100%;important: top: 0}

在這里,我們調用美國人口普查 API 來獲取每個 state 的人口,刪除華盛頓特區和波多黎各,將這些結果重新格式化為您的{state, population}輸入格式,然后使用值數組調用apportion (435) (如果您已經有該格式的數據,您可以調用apportion (435) ),它會為每個 state 分配一個席位,然后使用 Huntington-Hill 方法分配剩余的席位。

它通過不斷調用nextSeat來做到這一點,它將每個州的人口除以其當前席位數的幾何平均值和下一個更高的數字,然后選擇具有最大值的 state。

這不會將 Ramda 用於任何事情。 也許我們會用一些 Ramda 函數稍微清理一下(例如,用assoc('seat', 1)替換pop => ({...pop, seats: 1}) ),但它可能不會很大獲得。 我看到這個問題是因為我關注 Ramda 標簽。 但這里的重點是,如果您碰巧感興趣,實際的當前分配方法並不難實現。

你可以看到這種技術是如何用於比較不同大小的房子的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM