python عنوان - فهم وظيفة الخريطة




الرابع هي (5)

map(function, iterable, ...)

قم بتطبيق الوظيفة على كل عنصر من عناصر التكرار وإرجاع قائمة النتائج. إذا تم تمرير وسيطات إضافية قابلة للتكرار ، يجب أن تأخذ الدالة العديد من الوسيطات ويتم تطبيقها على العناصر من جميع المتكررات في نفس الوقت.

إذا كان أحد المتكررين أقصر من الآخر ، فمن المفترض أن يتم تمديده باستخدام عناصر بدون.

إذا كانت الوظيفة هي None ، فستفترض وظيفة الهوية ؛ إذا كانت هناك وسيطات متعددة ، map() تُرجع map() قائمة تتكون من مجموعات تحتوي على العناصر المقابلة من جميع المتكررات (نوع من عملية التحويل).

قد تكون الوسائط المتكرّرة عبارة عن تسلسل أو أي كائن قابل للتكرار ؛ والنتيجة هي دائما قائمة.

ما الدور الذي تلعبه هذه اللعبة في صنع منتج ديكارت؟

content = map(tuple, array)

ما هو تأثير وضع مجموعة الصفوف في أي مكان؟ كما أنني لاحظت أنه بدون وظيفة الخريطة يكون الإخراج هو abc ومعه ، إنه a, b, c .

أريد أن أفهم تماما هذه الوظيفة. التعريفات المرجعية يصعب فهمها أيضًا. زغب كثير جدا.


Answers

لا ترتبط map بمنتج ديكارت على الإطلاق ، على الرغم من أنني أتخيل أن شخصا ما على دراية بالبرمجة الوظيفية قد يأتي ببعض المستحيل فهم طريقة توليد map باستخدام واحدة.

map في Python 3 تعادل هذا:

def map(func, iterable):
    for i in iterable:
        yield func(i)

والفرق الوحيد في بايثون 2 هو أنه سيبني قائمة كاملة بالنتائج لإرجاعها دفعة واحدة بدلاً من yield على yield .

على الرغم من أن إتفاقية بايثون تفضل عادةً فهم القوائم (أو تعبيرات المولدات) لتحقيق نفس النتيجة مثل استدعاء map ، خاصة إذا كنت تستخدم تعبير لامدا كوسيطة أولى:

[func(i) for i in iterable]

كمثال على ما طلبته في التعليقات على السؤال - "تحويل سلسلة إلى مصفوفة" ، من خلال "المصفوفة" ربما تريد إما مجموعة أو قائمة (كلاهما يتصرفان قليلاً مثل المصفوفات من اللغات الأخرى) -

 >>> a = "hello, world"
 >>> list(a)
['h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
>>> tuple(a)
('h', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd')

سيكون استخدام map هنا إذا بدأت بقائمة من السلاسل بدلاً من سلسلة واحدة - يمكن map أن تضع كل منها على حدة:

>>> a = ["foo", "bar", "baz"]
>>> list(map(list, a))
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

لاحظ أن map(list, a) متساوية في Python 2 ، ولكن في Python 3 ، تحتاج إلى استدعاء list إذا كنت تريد القيام بأي شيء آخر غير إطعامها في حلقة for (أو دالة معالجة مثل sum يحتاج فقط إلى iterable وليس تسلسلًا). ولكن لاحظ أيضًا مرة أخرى أن الفهم بالقائمة يُفضل عادةً:

>>> [list(b) for b in a]
[['f', 'o', 'o'], ['b', 'a', 'r'], ['b', 'a', 'z']]

map ليست pythonic بشكل خاص. أوصيك باستخدام فهرسة القوائم بدلاً من ذلك:

map(f, iterable)

يعادل بشكل أساسي ما يلي:

[f(x) for x in iterable]

map من تلقاء نفسها لا يمكن القيام بمنتج الديكارتي ، لأن طول قائمة المخرجات هو دائما نفس قائمة المدخلات. يمكنك عمل منتج ديكارتي بشكل تافه باستخدام قائمة من الفهم على الرغم من:

[(a, b) for a in iterable_a for b in iterable_b]

إن التركيب اللغوي مربك إلى حد ما - وهذا يعادل بشكل أساسي ما يلي:

result = []
for a in iterable_a:
    for b in iterable_b:
        result.append((a, b))

تبسيط قليلا ، يمكنك تخيل map() القيام بشيء من هذا القبيل:

def mymap(func, lst):
    result = []
    for e in lst:
        result.append(func(e))
    return result

كما ترى ، فإنه يأخذ وظيفة وقائمة ، ويعيد قائمة جديدة بنتيجة تطبيق الوظيفة على كل عنصر من عناصر قائمة الإدخال. قلت "تبسيط قليلا" لأنه في الواقع يمكن map() معالجة أكثر من واحد ممكن:

إذا تم تمرير وسيطات إضافية قابلة للتكرار ، يجب أن تأخذ الدالة العديد من الوسيطات ويتم تطبيقها على العناصر من جميع المتكررات في نفس الوقت. إذا كان أحد المتكررين أقصر من الآخر ، فمن المفترض أن يتم تمديده باستخدام عناصر بدون.

بالنسبة للجزء الثاني من السؤال: ما الدور الذي تلعبه هذه اللعبة في صنع منتج ديكارت؟ كذلك ، يمكن استخدام map() لتوليد المنتج الديكارتية لقائمة مثل هذه:

lst = [1, 2, 3, 4, 5]

from operator import add
reduce(add, map(lambda i: map(lambda j: (i, j), lst), lst))

... لكن قول الحقيقة ، إن استخدام product() هو طريقة أبسط وطبيعية لحل المشكلة:

from itertools import product
list(product(lst, lst))

في كلتا الحالتين ، والنتيجة هي المنتج الديكارتية ل lst النحو المحدد أعلاه:

[(1, 1), (1, 2), (1, 3), (1, 4), (1, 5),
 (2, 1), (2, 2), (2, 3), (2, 4), (2, 5),
 (3, 1), (3, 2), (3, 3), (3, 4), (3, 5),
 (4, 1), (4, 2), (4, 3), (4, 4), (4, 5),
 (5, 1), (5, 2), (5, 3), (5, 4), (5, 5)]

map بإنشاء قائمة جديدة عن طريق تطبيق دالة على كل عنصر من عناصر المصدر:

xs = [1, 2, 3]

# all of those are equivalent — the output is [2, 4, 6]
# 1. map
ys = map(lambda x: x * 2, xs)
# 2. list comprehension
ys = [x * 2 for x in xs]
# 3. explicit loop
ys = []
for x in xs:
    ys.append(x * 2)

تكافئ map n-ary إدخال سداسيات الإدخال المتكرر معًا ثم تطبيق وظيفة التحويل على كل عنصر من عناصر تلك القائمة المضغوطة المتوسطة. إنه ليس منتجًا ديكارتًا:

xs = [1, 2, 3]
ys = [2, 4, 6]

def f(x, y):
    return (x * 2, y // 2)

# output: [(2, 1), (4, 2), (6, 3)]
# 1. map
zs = map(f, xs, ys)
# 2. list comp
zs = [f(x, y) for x, y in zip(xs, ys)]
# 3. explicit loop
zs = []
for x, y in zip(xs, ys):
    zs.append(f(x, y))

لقد استعملت zip هنا ، لكن سلوك map يختلف في الواقع قليلاً عندما لا تكون iterables بنفس الحجم - كما هو مذكور في وثائقها ، فهي تمدد التكرار لاحتواء None .


ماذا عن بطانة واحدة مع تخصيص متغير مباشرة في JS عادي ( ES6 / ES2015

الاستفادة من استخدام عامل التوسيع وعمود اسم المفتاح المحسوب :

let newObj = Object.assign({}, ...Object.keys(obj).map(k => ({[k]: obj[k] * obj[k]})));

jsbin

إصدار آخر باستخدام تقليل:

let newObj = Object.keys(obj).reduce((p, c) => ({...p, [c]: obj[c] * obj[c]}), {});

jsbin

المثال الأول كدالة:

const oMap = (o, f) => Object.assign({}, ...Object.keys(o).map(k => ({ [k]: f(o[k]) })));

// To square each value you can call it like this:
let mappedObj = oMap(myObj, (x) => x * x);

jsbin

إذا كنت تريد تعيين كائن متداخل بشكل متكرر في نمط وظيفي ، فيمكن القيام به على النحو التالي:

const sqrObjRecursive = (obj) => 
  Object.keys(obj).reduce((newObj, key) => 
    (obj[key] && typeof obj[key] === 'object') ?
      {...newObj, [key]: sqrObjRecursive(obj[key])} :  // recurse.
      {...newObj, [key]: obj[key] * obj[key]}          // square val.
    ,{})       

jsbin

أو أكثر حتمًا ، مثل هذا:

const sqrObjRecursive = (obj) => {
  Object.keys(obj).forEach(key => {
    if (typeof obj[key] === 'object') obj[key] = sqrObjRecursive(obj[key]);
    else obj[key] = obj[key] * obj[key]
  });
  return obj;
};

jsbin

منذ ES7 / ES2016 يمكنك استخدام Object.entries بدلاً من Object.keys مثل هذا:

let newObj = Object.assign(...Object.entries(obj).map(([k, v]) => ({[k]: v * v})));


الخصائص الموروثة وسلسلة النموذج الأولي:

في بعض الحالات النادرة ، قد تحتاج إلى تعيين كائن شبيه بالطبقة يحمل خصائص كائن موروث على prototype-chain . في مثل هذه الحالات لن تعمل Object.keys() ، لأن Object.keys() لا يقوم Object.keys() الخصائص الموروثة . إذا كنت بحاجة إلى تعيين الخصائص الموروثة ، يجب أن تستخدمها for (key in myObj) {...} .

فيما يلي مثال لكائن يرث خصائص كائن آخر وكيف لا يعمل Object.keys() في هذا السيناريو.

const obj1 = { 'a': 1, 'b': 2, 'c': 3}
const obj2 = Object.create(obj1);  // One of multiple ways to inherit an object in JS.

// Here you see how the properties of obj1 sit on the 'prototype' of obj2
console.log(obj2)  // Prints: obj2.__proto__ = { 'a': 1, 'b': 2, 'c': 3}

console.log(Object.keys(obj2));  // Prints: an empty Array.

for (key in obj2) {
  console.log(key);              // Prints: 'a', 'b', 'c'
}

jsbin

ومع ذلك ، يرجى القيام لي معروفا وتجنب الميراث . :-)





python map-function