खाली तार '' बेतरतीब ढंग से कई सरणियों में रखे जाते हैं। मैं '' को data.X में मानों से बदलना चाहता हूं।

const data = {
  a: ['a', '', 'a', 'a', ''],
  b: ['b', 'b', ''],
  c: ['', '', 'c', 'c'],
  X: ['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']
}

मुझे उम्मीद है कि यह निम्नानुसार रूपांतरित होगा। कृपया ध्यान दें कि X1, X2 ... को a b c के सरणियों में रखा गया है।

const dataTransformed = {
  a: ['a', 'X1', 'a', 'a', 'X2'],
  b: ['b', 'b', 'X3'],
  c: ['X4', 'X5', 'c', 'c']
}

आप मान सकते हैं कि खाली स्ट्रिंग्स की संख्या को संतुष्ट करने के लिए पर्याप्त length of X हैं। मैं R.lensProp का परीक्षण कर रहा हूं, लेकिन ऐसा लगता है कि यह एकाधिक कुंजी लेने में असमर्थ है।

const replaceEmptyString = X => R.map(R.replace(/''/g, X)) 
const setX = R.map(R.over(R.lensProp('a', 'b', 'c'), replaceEmptyString)) 

const replaceStringsLens = R.lens(replaceEmptyString, setX)
console.log (replaceStringsLens(data)) //ERROR

मैं आपके मार्गदर्शन की सराहना करता हूं। REPL

1
Rio 24 अक्टूबर 2020, 14:32

2 जवाब

सबसे बढ़िया उत्तर

एक दिलचस्प तरीका राज्य को (डिफ़ॉल्ट) मापदंडों में रखना है:

const fillWithX = ({X, ...rest}, i = 0, next = () => X [i++] || '') => 
  R.map (R.map (v => v || next ()), rest)

const data = {
  a: ['a', '', 'a', 'a', ''],
  b: ['b', 'b', ''],
  c: ['', '', 'c', 'c'],
  X: ['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']
}

console .log (fillWithX (data))
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js"></script>

(ध्यान दें कि || '' उस मामले को संभालता है जहां पर्याप्त एक्स नहीं हैं। आप एक अलग डिफ़ॉल्ट, या कुछ अन्य हैंडलिंग पूरी तरह से चाहते हैं।)

यहां रामदा की map चमकती है, खासकर वस्तुओं से निपटने के लिए। हम बाहरी map को Object.entries -> Array.prototype.map -> Object.fromEntries के नृत्य से और आंतरिक वाले को Array.prototype.map से बदलकर रामदा को छोड़ सकते हैं, जैसे:

const fillWithX = ({X, ...rest}, i = 0, next = () => X [i++] || '') => 
  Object .fromEntries (
    Object .entries (rest) 
      .map (([k, vs]) => [k, vs .map (a => a || next ())])
  )

लेकिन यह निश्चित रूप से रामदा दृष्टिकोण से कम सुरुचिपूर्ण लगता है।


यहां दो चिंताएं हैं। सबसे पहले, डिफ़ॉल्ट पैरामीटर के साथ समस्याएं हो सकती हैं। यदि आपके पास तीन भिन्न data संस्करण थे, तो आप सफलतापूर्वक कॉल नहीं कर सकते

[data1, data2, data3] .map (fillWithX)

क्योंकि index तर्क कि Array.prototype.map अपने कॉलबैक को आपूर्ति करता है, i पैरामीटर को fillWithX पर ओवरराइड कर देगा और इसका array पैरामीटर next को ओवरराइड कर देगा। और केवल map ही ऐसा स्थान नहीं है जो ऐसा हो सकता है। मैं अक्सर इसे अनदेखा करना चुनता हूं यदि मुझे पता है कि मेरा कार्य कैसे कहा जाएगा। जब मुझे इससे निपटने की आवश्यकता होती है, तो मानक तकनीक एक निजी सहायक और एक सार्वजनिक कार्य लिखना है जो इसे केवल आवश्यक पैरामीटर के साथ कॉल करता है। लेकिन रामदा call ऑफर करता है, जो कभी-कभी इसे साफ-सुथरा बना सकता है। हम इसे इस तरह ठीक कर सकते हैं:

const fillWithX = (data) => R.call (
  ({X, ...rest}, i = 0, next = () => X [i++] || '') => 
    R.map (R.map (v => v || next ()), rest),
  data
)

यहां हम एक नया फ़ंक्शन बनाते हैं जो हमारे data पैरामीटर लेता है और R.call को उपरोक्त फ़ंक्शन और data तर्क के साथ कॉल करता है। यह काफी सार्वभौमिक तकनीक है।

दूसरी समस्या अधिक मौलिक है। मुझे यकीन नहीं है कि यह फ़ंक्शन वास्तव में समझ में आता है। यह कार्यान्वयन नहीं है; यह मूल विचार है। मुद्दा यह है कि सभी उचित उद्देश्यों के लिए, ये दो वस्तुएं समान हैं:

const data = {
  a: ['a', '', 'a', 'a', ''],
  b: ['b', 'b', ''],
  c: ['', '', 'c', 'c'],
  X: ['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']
}

तथा

const data = {
  b: ['b', 'b', ''],
  a: ['a', '', 'a', 'a', ''],
  c: ['', '', 'c', 'c'],
  X: ['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']
}

लेकिन यह फ़ंक्शन दोनों के लिए अलग-अलग मान देगा, क्योंकि चाबियाँ अलग-अलग क्रम में हैं।

यदि लक्ष्य केवल X से अलग-अलग मानों के साथ सभी छिद्रों को भरना है, तो यह कोई समस्या नहीं है। लेकिन यदि दिए गए छिद्रों में दिखाई देने वाले विशिष्ट X मान महत्वपूर्ण हैं, तो एक मूलभूत समस्या है। और एकमात्र व्यावहारिक समाधान जो मैं देखता हूं, उसमें चाबियों को छांटना शामिल होगा - एक बदसूरत और कुछ हद तक अनपेक्षित प्रक्रिया।

इसलिए मुझे लगता है कि आप इसे या विचार के किसी अन्य कार्यान्वयन का उपयोग करने से पहले इस मुद्दे पर थोड़ा विचार करना चाहेंगे।

एक पुनरावर्तक का उपयोग करना

एक टिप्पणी से धन्यवाद a> एक पुनरावर्तक का उपयोग करके उस स्थिति को संभालने का एक आसान तरीका इंगित करता है। .values() पर कॉल करके किसी भी ऐरे को इटरेटर में बदला जा सकता है। यह अंतर्निहित दृष्टिकोण निश्चित रूप से क्लीनर है:

const fillWithX = ({X, ...rest}, it = X .values()) => 
  R .map (R .map (v => v || it .next () .value || ''), rest)

इसमें अभी भी डिफ़ॉल्ट पैरामीटर के साथ समस्या है और यदि वांछित हो तो उसी तरह हल किया जा सकता है। और निश्चित रूप से यह ऊपर वर्णित मूलभूत मुद्दे को नहीं बदलता है।

लेकिन यह निश्चित रूप से क्लीनर है।

3
Scott Sauyet 28 अक्टूबर 2020, 23:45

चूंकि आपको X में वर्तमान स्थान को संरक्षित करने की आवश्यकता है, या घटना सरणी को बदल देती है, मुझे रामदा के साथ ऐसा करने में कोई फायदा नहीं दिखता है।

X को बाकी ऑब्जेक्ट से अलग करने के लिए डिस्ट्रक्टिंग का उपयोग करें, और स्प्रेड का उपयोग करके इसे क्लोन करें, इसलिए हम मूल ऑब्जेक्ट को म्यूट नहीं करेंगे।

शेष ऑब्जेक्ट से, Object.entries() (या R.toPairs) का उपयोग करके [key, value] जोड़े की एक सरणी प्राप्त करें, जोड़े को मैप करें, और प्रत्येक जोड़ी की सरणी को मैप करें (v) . यदि कोई आइटम खाली है, तो क्लोन किए गए X से मूल्य प्राप्त करने के लिए Array.shift() का उपयोग करें।

Object.fromEntries() का उपयोग करके किसी ऑब्जेक्ट में वापस कनवर्ट करें।

const fn = ({ X, ...rest }) => {
  const x = [...X] // clone X to avoid mutating the original
  
  return Object.fromEntries( // convert back to object
    Object.entries(rest) // convert to pairs of [key, value]
      .map(([k, v]) => // map the pairs
        // map the values and replace empty values from the cloned X array
        [k, v.map(item => item || x.shift())]
      )
  )
}

const data = {
  a: ['a', '', 'a', 'a', ''],
  b: ['b', 'b', ''],
  c: ['', '', 'c', 'c'],
  X: ['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']
}

const result = fn(data)

console.log(result)

और जैसा कि बताया गया है @ScottSauyet, R.map का उपयोग करके कम क्रिया बनाता है:

const fn = ({ X, ...rest }) => {
  const x = [...X] // clone X to avoid mutating the original
  // map the values and replace empty values from the cloned X array
  return R.map(v => v.map(item => item || x.shift()), rest)
}

const data = {
  a: ['a', '', 'a', 'a', ''],
  b: ['b', 'b', ''],
  c: ['', '', 'c', 'c'],
  X: ['X1', 'X2', 'X3', 'X4', 'X5', 'X6', 'X7', 'X8']
}

const result = fn(data)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous"></script>
3
Ori Drori 24 अक्टूबर 2020, 19:07