array_map ของ PHP รวมถึงปุ่มต่างๆ


208

มีวิธีทำสิ่งนี้ไหม:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map(function($a, $b) { return "$a loves $b"; }, 
         array_keys($test_array), 
         array_values($test_array)));

แต่แทนที่จะโทรarray_keysและarray_valuesส่งผ่านโดยตรง$test_arrayตัวแปรหรือไม่

ผลลัพธ์ที่ต้องการคือ:

array(2) {
  [0]=>
  string(27) "first_key loves first_value"
  [1]=>
  string(29) "second_key loves second_value"
}

ดูเพิ่มเติมที่: stackoverflow.com/search?q=each_with_indexสำหรับแนวทางที่ตรงกันข้ามกับปัญหาทั่วไปนี้
dreftymac

คำตอบ:


206

ไม่ได้อยู่ใน array_map เนื่องจากไม่ได้จัดการกับกุญแจ

array_walkทำ:

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");
array_walk($test_array, function(&$a, $b) { $a = "$b loves $a"; });
var_dump($test_array);

// array(2) {
//   ["first_key"]=>
//   string(27) "first_key loves first_value"
//   ["second_key"]=>
//   string(29) "second_key loves second_value"
// }

มันจะเปลี่ยนอาร์เรย์ที่กำหนดเป็นพารามิเตอร์อย่างไรก็ตามมันจึงไม่ใช่การเขียนโปรแกรมที่ใช้งานได้จริง (เนื่องจากคุณมีคำถามที่ติดแท็กแบบนั้น) นอกจากนี้ตามที่ระบุไว้ในความคิดเห็นสิ่งนี้จะเปลี่ยนค่าของอาร์เรย์เท่านั้นดังนั้นคีย์จะไม่เป็นสิ่งที่คุณระบุในคำถาม

คุณสามารถเขียนฟังก์ชั่นที่แก้ไขคะแนนด้านบนของคุณได้ถ้าคุณต้องการเช่นนี้

function mymapper($arrayparam, $valuecallback) {
  $resultarr = array();
  foreach ($arrayparam as $key => $value) {
    $resultarr[] = $valuecallback($key, $value);
  }
  return $resultarr;
}

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");
$new_array = mymapper($test_array, function($a, $b) { return "$a loves $b"; });
var_dump($new_array);

// array(2) {
//   [0]=>
//   string(27) "first_key loves first_value"
//   [1]=>
//   string(29) "second_key loves second_value"
// }

ยกเว้นในกรณีนี้คุณต้องการ$a = "$b loves $a"ให้ตรงกับผลลัพธ์ที่ต้องการของ OP
cmbuckley

1
ถูกต้องเปลี่ยนแล้ว :) มันดีนะที่พวกเขาสร้าง array_map จาก array_walk
eis

ขอบคุณมาก เพื่อหลีกเลี่ยงการสับสนอาเรย์ดั้งเดิมนี่คือสิ่งที่ฉันทำในที่สุด (ดูคำตอบของฉันด้านล่าง)
JoséTomás Tocino

3
นี่ไม่ใช่ "functional-programming" แม้ว่าarray_walk()จะไม่ส่งคืนอาร์เรย์ผลลัพธ์ แต่เป็นการบูลแทน
แม่

@ ใช่ใช่เหมือนที่ฉันเขียนไว้ในคำตอบเช่นกัน - แทนที่จะส่งคืนค่ามันจะเปลี่ยนพารามิเตอร์
eis

145

นี่อาจเป็นเหตุผลสั้นที่สุดและง่ายที่สุดในการ:

$states = array('az' => 'Arizona', 'al' => 'Alabama');

array_map(function ($short, $long) {
    return array(
        'short' => $short,
        'long'  => $long
    );
}, array_keys($states), $states);

// produces:
array(
     array('short' => 'az', 'long' => 'Arizona'), 
     array('short' => 'al', 'long' => 'Alabama')
)

15
array_keys()ฉันเพิ่งตระหนักว่าคำถามเฉพาะกล่าวว่าจะไม่ใช้ ที่ดูเหมือนว่าต้องการโง่ แต่
Kevin Beal

3
คำถามที่ให้วิธีการแก้ปัญหาโดยใช้ array_keys () มันจะโง่ที่จะให้คำตอบที่ไม่มีประโยชน์ (เช่นการเรียกฟังก์ชั่นน้อยลง) มากกว่าการแก้ปัญหาในปัจจุบัน
Chinoto Vokro

คำตอบสำหรับคำถามเดิมคือไม่และนี่คือทางออกที่เหมาะสมที่สุด
usoban

65

ต่อไปนี้เป็นโซลูชันที่ใช้งานร่วมกับ PHP 5.5 ได้อย่างง่ายดาย

function array_map_assoc(callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
}

callable return [key, value]คุณให้ตัวเองควรจะกลับอาร์เรย์มีสองค่าคือ การโทรภายในเพื่อarray_mapสร้างอาร์เรย์ของอาร์เรย์ สิ่งนี้จะถูกแปลงกลับไปเป็นอาเรย์แบบมิติเดียวโดยarray_columnนี้จากนั้นจะได้รับกลับมาแปลงเป็นแถวเดียวมิติโดย

การใช้

$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

$func = function ($k, $v) {
    return ['new ' . $k, 'new ' . $v];
};

var_dump(array_map_assoc($func, $ordinals));

เอาท์พุต

array(3) {
  ["new first"]=>
  string(7) "new 1st"
  ["new second"]=>
  string(7) "new 2nd"
  ["new third"]=>
  string(7) "new 3rd"
}

แอปพลิเคชั่นบางส่วน

ในกรณีที่คุณจำเป็นต้องใช้ฟังก์ชั่นหลาย ๆ ครั้งที่มีอาร์เรย์ที่แตกต่างกัน แต่ฟังก์ชั่นการทำแผนที่เดียวกันคุณสามารถทำสิ่งที่เรียกว่าฟังก์ชั่นบางส่วน (ที่เกี่ยวข้องกับ ' currying ') ซึ่งช่วยให้คุณผ่านในอาร์เรย์ข้อมูล

function array_map_assoc_partial(callable $f) {
    return function (array $a) use ($f) {
        return array_column(array_map($f, array_keys($a), $a), 1, 0);
    };
}

...
$my_mapping = array_map_assoc_partial($func);
var_dump($my_mapping($ordinals));

ซึ่งสร้างผลลัพธ์เดียวกันให้$funcและ$ordinalsเป็นก่อนหน้านี้

หมายเหตุ: หากฟังก์ชั่นที่แมปของคุณส่งคืนคีย์เดียวกันสำหรับอินพุตที่แตกต่างกันสองรายการค่าที่เกี่ยวข้องกับคีย์ภายหลังจะเป็นผู้ชนะ ย้อนกลับอาร์เรย์อินพุตและผลลัพธ์ผลลัพธ์ของarray_map_assocการอนุญาตให้คีย์ก่อนหน้าชนะ (คีย์ที่ส่งคืนในตัวอย่างของฉันไม่สามารถชนกันได้เนื่องจากพวกเขารวมคีย์ของอาร์เรย์ต้นฉบับซึ่งจะต้องไม่ซ้ำกัน)


ทางเลือก

ต่อไปนี้เป็นตัวแปรด้านบนซึ่งอาจพิสูจน์ได้ว่ามีเหตุผลมากกว่าบางตัว แต่ต้องการ PHP 5.6:

function array_map_assoc(callable $f, array $a) {
    return array_merge(...array_map($f, array_keys($a), $a));
}

ในตัวแปรนี้ฟังก์ชั่นที่ให้มาของคุณ (ซึ่งมีการแม็พข้อมูลอาร์เรย์) ควรส่งคืนอาเรย์ที่เชื่อมโยงกับหนึ่งแถวreturn [key => value]แทน ผลของการทำแผนที่ callable array_mergeเป็นแล้วก็แตกและส่งผ่านไปยัง ก่อนหน้านี้การส่งคืนคีย์ที่ซ้ำกันจะส่งผลให้ได้รับรางวัลในภายหลัง

nb Alex83690 ได้ระบุไว้ในความคิดเห็นว่าการใช้array_replaceที่นี่แทนการarray_mergeเก็บรักษาคีย์จำนวนเต็ม array_replaceไม่ได้แก้ไขอาร์เรย์อินพุตดังนั้นจึงปลอดภัยสำหรับโค้ดการทำงาน

หากคุณใช้ PHP 5.3 ถึง 5.5 สิ่งต่อไปนี้จะเทียบเท่า มันใช้array_reduceและตัว+ดำเนินการอาร์เรย์แบบไบนารีเพื่อแปลงอาร์เรย์แบบสองมิติที่เป็นผลลัพธ์ลงในอาร์เรย์แบบหนึ่งมิติในขณะที่ยังคงคีย์ไว้:

function array_map_assoc(callable $f, array $a) {
    return array_reduce(array_map($f, array_keys($a), $a), function (array $acc, array $a) {
        return $acc + $a;
    }, []);
}

การใช้

ตัวแปรทั้งสองนี้จะใช้ดังนี้:

$ordinals = [
    'first' => '1st',
    'second' => '2nd',
    'third' => '3rd',
];

$func = function ($k, $v) {
    return ['new ' . $k => 'new ' . $v];
};

var_dump(array_map_assoc($func, $ordinals));

หมายเหตุ=>แทนใน,$func

เอาต์พุตเหมือนก่อนหน้าและแต่ละอันสามารถนำไปใช้บางส่วนได้ในลักษณะเดียวกับก่อนหน้านี้


 สรุป

เป้าหมายของคำถามเดิมคือการเรียกใช้การโทรที่ง่ายที่สุดเท่าที่จะเป็นไปได้โดยเสียค่าใช้จ่ายในการมีฟังก์ชั่นที่ซับซ้อนมากขึ้นที่ถูกเรียกใช้ โดยเฉพาะอย่างยิ่งการมีความสามารถในการส่งผ่านอาร์เรย์ข้อมูลเป็นอาร์กิวเมนต์เดียวโดยไม่ต้องแยกคีย์และค่า การใช้ฟังก์ชั่นที่ให้มาในตอนต้นของคำตอบนี้:

$test_array = ["first_key" => "first_value",
               "second_key" => "second_value"];

$array_map_assoc = function (callable $f, array $a) {
    return array_column(array_map($f, array_keys($a), $a), 1, 0);
};

$f = function ($key, $value) {
    return [$key, $key . ' loves ' . $value];
};

var_dump(array_values($array_map_assoc($f, $test_array)));

หรือสำหรับคำถามนี้เท่านั้นเราสามารถทำให้array_map_assoc()ฟังก์ชั่นที่ทำให้คีย์เอาต์พุตง่ายขึ้นเนื่องจากคำถามไม่ได้ถามพวกเขา:

$test_array = ["first_key" => "first_value",
               "second_key" => "second_value"];

$array_map_assoc = function (callable $f, array $a) {
    return array_map($f, array_keys($a), $a);
};

$f = function ($key, $value) {
    return $key . ' loves ' . $value;
};

var_dump($array_map_assoc($f, $test_array));

ดังนั้นคำตอบคือไม่คุณไม่สามารถหลีกเลี่ยงการโทรarray_keysได้ แต่คุณสามารถสรุปสถานที่ที่array_keysได้รับการโทรเข้าสู่ฟังก์ชั่นการสั่งซื้อที่สูงขึ้นซึ่งอาจจะดีพอ


7
ดูเหมือนว่าควรทำเครื่องหมายเป็นคำตอบที่ถูกต้อง
eddiewould

6
ขอบคุณ @eddould แต่ฉันประมาณ4½ปีที่แล้วสายเกินไป :) ฉันมาที่นี่เพื่อหาทางแก้ปัญหาไม่พบสิ่งที่ฉันชอบเลยมาด้วยตัวฉันเอง
Nicholas Shanks

1
ฉันจะเป็นผู้ชายคนนั้น PHP 5.3 ไม่ควรเป็นข้อกำหนดสำหรับวันที่ของคำตอบนี้อีกต่อไป IMHO
Erutan409

1
โซลูชันทางเลือกแรกของคุณไม่ถูกต้อง คุณต้องแทนที่array_mergeด้วยarray_replaceเพื่อเก็บรักษาคีย์ที่จะเป็นจำนวนเต็ม
Alex83690

1
@ Alex83690 ขอบคุณ! แม้ว่าฉันจะบอกว่า "ไม่ถูกต้อง" นั้นทำให้เข้าใจผิดเล็กน้อย - มันก็ดีถ้าคุณไม่มีคีย์จำนวนเต็มใด ๆ (ตามความเป็นจริงในกรณีของฉันเอง)
Nicholas Shanks

20

ด้วย PHP5.3 หรือใหม่กว่า:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(
    array_map(
        function($key) use ($test_array) { return "$key loves ${test_array[$key]}"; },
        array_keys($test_array)
    )
);

1
ฉันคิดว่าสิ่งที่ต้องการคือ "แทนที่จะเรียกใช้ array_keys และ array_values ​​โดยตรงผ่านตัวแปร $ test_array" สิ่งนี้สามารถใช้งานได้โดยไม่ต้องใช้ array_keys?
eis

4

นี่คือวิธีที่ฉันใช้ในโครงการของฉัน

function array_map_associative(callable $callback, $array) {
    /* map original array keys, and call $callable with $key and value of $key from original array. */
    return array_map(function($key) use ($callback, $array){
        return $callback($key, $array[$key]);
    }, array_keys($array));
}

สะอาดมากและไม่เปลี่ยนแปลงอาเรย์ดั้งเดิม!
Raffaele Candeliere

4

ดูนี่! มีทางออกเล็กน้อย!

function array_map2(callable $f, array $a)
{
    return array_map($f, array_keys($a), $a);
}

ตามที่ระบุไว้ในคำถามarray_map แล้วมีฟังก์ชั่นที่จำเป็นอย่างแน่นอน คำตอบอื่น ๆ ที่นี่อย่างจริงจัง overcomplicate สิ่ง: array_walkไม่ทำงาน

การใช้

ตรงตามที่คุณคาดหวังจากตัวอย่างของคุณ:

$test_array = array("first_key" => "first_value", 
                    "second_key" => "second_value");

var_dump(array_map2(function($a, $b) { return "$a loves $b"; }, $test_array));

คำตอบอื่น ๆ ที่ซับซ้อนเกินไปเพราะคำถามที่ระบุqrrqy_keys()ไม่ควรใช้สำหรับ #reasons
Brad Kent

2

โดย "คู่มือห่วง" foreachฉันหมายถึงเขียนฟังก์ชั่นที่กำหนดเองที่ใช้ สิ่งนี้จะส่งคืนอาร์เรย์ใหม่อย่างที่เป็นเช่นarray_mapนั้นเพราะขอบเขตของฟังก์ชันทำให้$arrayสำเนานั้นไม่ใช่การอ้างอิง:

function map($array, callable $fn) {
  foreach ($array as $k => &$v) $v = call_user_func($fn, $k, $v);
  return $array;
}

เทคนิคของคุณที่ใช้array_mapกับarray_keysดูเหมือนจริงง่ายกว่าและมีประสิทธิภาพมากขึ้นเพราะคุณสามารถใช้nullเป็นโทรกลับเพื่อส่งกลับคู่คีย์ - ค่า:

function map($array, callable $fn = null) {
  return array_map($fn, array_keys($array), $array);
}

อาร์เรย์ลูปที่มีการอ้างอิงสามารถทำให้สิ่งต่าง ๆ น่ากลัวเกิดขึ้นได้
janenz00

มันไม่น่ากลัวมันแค่หมายความว่าคุณลืมunset( $value )เพราะมันยังคงอยู่ในขอบเขตที่กำหนด
aziz punjani

@azis ถูกล้อเล่นเกี่ยวกับความน่ากลัวหมายถึงบทความ มันจะสร้างเอฟเฟกต์ที่ไม่คาดคิดถ้าคุณลืมที่จะยกเลิก
janenz00

1
ขอบคุณสำหรับคำตอบ แต่ฉันคิดว่ามันค่อนข้างชัดเจนว่าฉันไม่ต้องการใช้วงแบบดั้งเดิม
JoséTomás Tocino

@ janenz00 ดูคำตอบที่แก้ไขแล้วเพื่อความกระจ่าง ฉันหมายถึงการวนลูปในขอบเขตตัวแปรที่สะอาด
ryanve

1

ตามคำตอบของ eisนี่คือสิ่งที่ฉันทำในที่สุดเพื่อหลีกเลี่ยงการสับสนอาร์เรย์เดิม:

$test_array = array("first_key" => "first_value",
                    "second_key" => "second_value");

$result_array = array();
array_walk($test_array, 
           function($a, $b) use (&$result_array) 
           { $result_array[] = "$b loves $a"; }, 
           $result_array);
var_dump($result_array);

2
ทำไมสิ่งนี้ง่ายกว่าเพียงแค่ส่งค่าอาร์เรย์และคีย์ไปยัง array_map โดยตรง มันช้าและซับซ้อนกว่าฉันไม่เห็นข้อได้เปรียบ
Ariel

1
@Ariel คุณสามารถสำรองข้อมูลอ้างว่ามันจะช้ากว่าแม้จะมีจำนวนมากใช่ไหม มันต้องย้ำอาเรย์เพียงครั้งเดียวดังนั้นฉันคิดว่ามันควรมีขนาดเร็วขึ้นในสัญกรณ์ O ขนาดใหญ่ ฉันเห็นด้วยเกี่ยวกับความซับซ้อนว่า
EIS

@eis มันช้าลงเพราะมันสร้างอาร์เรย์ผลลัพธ์ทีละรายการใน PHP แทนที่จะเป็น en masse ใน C มันจะหลีกเลี่ยงการเรียก array_keys ได้ (แม้ว่าจะรวดเร็วเพราะอยู่ใน C) เกณฑ์มาตรฐาน - ดูว่าเร็วกว่าใครฉันไม่แน่ใจจริงๆ แต่โดยปกติแล้วโค้ดเพิ่มเติม = รหัสช้าลง ในความซับซ้อนมันยิ่งแย่ลงกว่าเดิมและสำคัญกว่าความเร็วเกือบตลอดเวลา
Ariel

1
คุณไม่จำเป็นต้องส่งอาร์กิวเมนต์ที่สามarray_walkเนื่องจากคุณไม่ได้อ้างอิงในตอนท้าย
Steven Lu

1

ฉันทำฟังก์ชันนี้ตามคำตอบของ eis :

function array_map_($callback, $arr) {
    if (!is_callable($callback))
        return $arr;

    $result = array_walk($arr, function(&$value, $key) use ($callback) {
        $value = call_user_func($callback, $key, $value);
    });

    if (!$result)
        return false;

    return $arr;
}

ตัวอย่าง:

$test_array = array("first_key" => "first_value", 
                "second_key" => "second_value");

var_dump(array_map_(function($key, $value){
    return $key . " loves " . $value;
}, $arr));

เอาท์พุท:

array (
  'first_key' => 'first_key loves first_value,
  'second_key' => 'second_key loves second_value',
)

นอกหลักสูตรคุณสามารถใช้array_valuesเพื่อคืนสิ่งที่ OP ต้องการได้อย่างแน่นอน

array_values(array_map_(function($key, $value){
    return $key . " loves " . $value;
}, $test_array))

@KevinBeal ฉันใช้ฟังก์ชั่นนี้เป็นอย่างมากในการทำงานของฉัน คุณช่วยชี้ว่าข้อผิดพลาดอยู่ที่ไหน?
Julio Vedovatto

2
ประการแรกรหัสในขณะที่มันหายไปตรวจสอบว่า$arrเป็นประเภทอาร์เรย์ แต่ถ้าคุณพิมพ์คำใบ้ข้อโต้แย้งของคุณเป็นcallableและarrayคุณสามารถวางเช็คis_callableแทน ถัดไปคุณทำการกำหนดค่าเป็น $ ที่ไม่ได้ใช้ คุณควรละเว้นค่าส่งคืน ประการที่สามมันจะดีกว่าที่จะโยนข้อยกเว้นในการโทรกลับกว่ากลับเท็จ จากนั้นคุณจะส่งคืนค่าที่ถูกต้องเสมอ
Nicholas Shanks

1

YaLinqo library * เหมาะสำหรับงานประเภทนี้ มันเป็นพอร์ตของ LINQ จาก. NET ที่รองรับค่าและคีย์ในการเรียกกลับทั้งหมดและคล้ายกับ SQL ตัวอย่างเช่น:

$mapped_array = from($test_array)
    ->select(function ($v, $k) { return "$k loves $v"; })
    ->toArray();

หรือเพียงแค่:

$mapped_iterator = from($test_array)->select('"$k loves $v"');

นี่'"$k loves $v"'คือทางลัดสำหรับซินแท็กซ์ปิดเต็มซึ่งห้องสมุดนี้สนับสนุน toArray()ในที่สุดก็เป็นตัวเลือก ห่วงโซ่วิธีการส่งกลับ iterator ดังนั้นหากผลเพียงแค่ต้องการที่จะได้รับมากกว่าการใช้ซ้ำforeach, toArrayโทรสามารถถอดออกได้

* พัฒนาโดยฉัน


1

ฉันจะทำสิ่งนี้:

<?php

/**
 * array_map_kv()
 *   An array mapping function to map with both keys and values.
 *
 * @param $callback callable
 *   A callback function($key, $value) for mapping values.
 * @param $array array
 *   An array for mapping.
 */
function array_map_kv(callable $callback, array $array) {
  return array_map(
    function ($key) use ($callback, $array) {
      return $callback($key, $array[$key]); // $callback($key, $value)
    },
    array_keys($array)
  );
}

// use it
var_dump(array_map_kv(function ($key, $value) {
  return "{$key} loves {$value}";
}, array(
  "first_key" => "first_value",
  "second_key" => "second_value",
)));

?>

ผล:

array(2) {
  [0]=>
  string(27) "first_key loves first_value"
  [1]=>
  string(29) "second_key loves second_value"
}

1

ฉันจะเพิ่มวิธีแก้ไขปัญหาอื่นโดยใช้เวอร์ชัน 5.6 หรือใหม่กว่า ไม่ทราบว่ามีประสิทธิภาพมากกว่าโซลูชันที่ยอดเยี่ยมอยู่แล้ว (อาจไม่ใช่) แต่สำหรับฉันแล้วมันอ่านง่ายกว่า:

$myArray = [
    "key0" => 0,
    "key1" => 1,
    "key2" => 2
];

array_combine(
    array_keys($myArray),
    array_map(
        function ($intVal) {
            return strval($intVal);
        },
        $myArray
    )
);

ใช้strval()เป็นฟังก์ชั่นตัวอย่างในการarray_mapนี้จะสร้าง:

array(3) {
  ["key0"]=>
  string(1) "0"
  ["key1"]=>
  string(1) "1"
  ["key2"]=>
  string(1) "2"
}

หวังว่าฉันไม่ใช่คนเดียวที่พบว่ามันง่ายที่จะเข้าใจ array_combineสร้างkey => valueอาเรย์จากอาเรย์ของคีย์และอาเรย์ของค่าส่วนที่เหลือเป็นคำอธิบายตัวเองสวย


1

คุณสามารถใช้วิธีการแมปจากไลบรารีอาเรย์นี้เพื่อให้ได้สิ่งที่คุณต้องการได้อย่างง่ายดายเช่น:

Arr::map($test_array, function($a, $b) { return "$a loves $b"; });

นอกจากนี้ยังเก็บรักษาคีย์และส่งกลับอาร์เรย์ใหม่ไม่ต้องพูดถึงโหมดที่แตกต่างกันเล็กน้อยเพื่อให้เหมาะกับความต้องการของคุณ



0

ฉันชอบแผนที่จาวาสคริปต์หลากหลายรูปแบบ เวอร์ชันที่ง่ายที่สุดคือ:

/**
 * @param  array    $array
 * @param  callable $callback
 * @return array
 */
function arrayMap(array $array, callable $callback)
{
    $newArray = [];

    foreach( $array as $key => $value )
    {
        $newArray[] = call_user_func($callback, $value, $key, $array);
    }

    return $newArray;
}

ดังนั้นตอนนี้คุณสามารถผ่านฟังก์ชันการเรียกกลับไปยังวิธีสร้างค่าได้

$testArray = [
    "first_key" => "first_value", 
    "second_key" => "second_value"
];

var_dump(
    arrayMap($testArray, function($value, $key) {
        return $key . ' loves ' . $value;
    });
);

มันจะมีประโยชน์มากขึ้นที่จะมีข้อมูลเป็นอาร์กิวเมนต์สุดท้ายที่จะฟังก์ชั่นใด ๆ ที่คุณเขียนเป็นแล้วคุณสามารถสร้างฟังก์ชั่นใหม่ที่อบในบางโทรกลับเฉพาะ (พฤติกรรม) - คือคุณจะได้รับองค์ประกอบฟังก์ชั่นh(g(f($data)))ใช้fแล้วgแล้วhที่คุณ ข้อมูล. โดยทั่วไปถือว่าหลากหลายมากขึ้นในการเขียนโปรแกรมฟังก์ชั่นที่จะมีฟังก์ชั่นที่ดำเนินการเดียวกันกับข้อมูลนักดำน้ำกว่าที่จะมีฟังก์ชั่นที่ใช้ฟังก์ชั่นนักดำน้ำกับชุดข้อมูลคงที่
Nicholas Shanks

ในตัวอย่างของคุณคุณมีอาร์กิวเมนต์เพียง 1 ฟังก์ชันเท่านั้น ฉันพบว่าการใส่ข้อมูลเป็นอาร์กิวเมนต์แรกทำได้ง่ายกว่าเช่น array_filter, array_reduce และฟังก์ชันอาร์เรย์ใน javascript
blablabla

นั่นคือจุดของฉัน! โดยการส่งผ่านข้อมูลที่ผ่านมาจะช่วยให้คุณแกงฟังก์ชัน (สร้างฟังก์ชั่นใหม่ที่ผสมผสานการวนลูปกับการดำเนินงานที่เฉพาะเจาะจง) และนำไปใช้ว่าข้อมูลโดยการเรียกฟังก์ชั่นใหม่ที่มีพารามิเตอร์เดียว หลักการนี้อธิบายได้ดีกว่าที่ฉันสามารถทำได้ที่นี่ในคำตอบนี้: stackoverflow.com/a/5863222
Nicholas Shanks

การใช้ฟังก์ชั่นเขียนในภาษาอย่าง PHP ไม่ใช่ทางออกที่ดีกว่าสำหรับปัญหานี้หรือไม่?
blablabla

1
มันเป็นทางเลือก แต่ต้องการการลงทุนใน FP อย่างมากตัวอย่างเช่น: github.com/nickshanks/fp-php-talk/blob/master/lib.php#L24หรือนี่คือ: github.com/nickshanks/php-fp/blob /master/src/fp.php#L62
Nicholas Shanks

0

อีกวิธีในการทำเช่นนี้ด้วย (out) การถนอมกุญแจ:

$test_array = [
    "first_key"     => "first_value",
    "second_key"    => "second_value"
];

$f = function($ar) {
    return array_map(
        function($key, $val) {
            return "{$key} - {$val}";
        },
        array_keys($ar),
        $ar
    );
};

#-- WITHOUT preserving keys
$res = $f($test_array);

#-- WITH preserving keys
$res = array_combine(
    array_keys($test_array),
    $f($test_array)
);

-2

ฉันเห็นว่ามันไม่มีคำตอบที่ชัดเจน:

function array_map_assoc(){
    if(func_num_args() < 2) throw new \BadFuncionCallException('Missing parameters');

    $args = func_get_args();
    $callback = $args[0];

    if(!is_callable($callback)) throw new \InvalidArgumentException('First parameter musst be callable');

    $arrays = array_slice($args, 1);

    array_walk($arrays, function(&$a){
        $a = (array)$a;
        reset($a);
    });

    $results = array();
    $max_length = max(array_map('count', $arrays));

    $arrays = array_map(function($pole) use ($max_length){
        return array_pad($pole, $max_length, null);
    }, $arrays);

    for($i=0; $i < $max_length; $i++){
        $elements = array();
        foreach($arrays as &$v){
            $elements[] = each($v);
        }
        unset($v);

        $out = call_user_func_array($callback, $elements);

        if($out === null) continue;

        $val = isset($out[1]) ? $out[1] : null;

        if(isset($out[0])){
            $results[$out[0]] = $val;
        }else{
            $results[] = $val;
        }
    }

    return $results;
}

ทำงานเหมือนกับ array_map เกือบจะ

จริงๆแล้วมันไม่บริสุทธิ์mapอย่างที่คุณรู้จากภาษาอื่น php แปลกมากดังนั้นมันจึงต้องการฟังก์ชั่นผู้ใช้ที่แปลกมากเพราะเราไม่ต้องการแยกworse is betterวิธีการที่แตกหัก

จริงๆแล้วมันไม่ได้เป็นความจริงmapเลย แต่มันก็ยังมีประโยชน์มาก

  • ความแตกต่างที่เห็นได้ชัดอันดับแรกจาก array_map คือการเรียกกลับใช้เอาต์พุตeach()จากทุกอาร์เรย์อินพุตแทนค่าเพียงอย่างเดียว คุณยังสามารถวนซ้ำในแต่ละอาร์เรย์ได้ในคราวเดียว

  • ข้อแตกต่างที่สองคือวิธีการจัดการคีย์หลังจากส่งคืนจากการโทรกลับ array('new_key', 'new_value')ค่าตอบแทนจากฟังก์ชันการเรียกกลับควรจะเป็น คีย์สามารถและจะมีการเปลี่ยนแปลงคีย์เดียวกันอาจทำให้ค่าก่อนหน้านี้ถูกเขียนทับหากคีย์เดียวกันถูกส่งคืน นี่ไม่ใช่mapลักษณะการทำงานทั่วไปแต่จะช่วยให้คุณสามารถเขียนคีย์ใหม่ได้

  • สิ่งที่สามที่แปลกคือถ้าคุณไม่ใส่keyค่าที่ส่งคืน (ไม่ว่าจะด้วยarray(1 => 'value')หรือarray(null, 'value')) จะมีการกำหนดคีย์ใหม่ราวกับว่า$array[] = $valueมีการใช้งาน นั่นเป็นmapพฤติกรรมที่ไม่เหมือนกัน แต่บางครั้งฉันก็คิดว่าเป็นประโยชน์

  • สิ่งที่สี่คือถ้าฟังก์ชั่นโทรกลับไม่ส่งคืนค่าหรือส่งคืนnullชุดคีย์และค่าปัจจุบันทั้งหมดจะถูกตัดออกจากเอาต์พุตมันจะถูกข้ามไป ฟีเจอร์นี้ไม่ได้แยกกันโดยสิ้นเชิงmapแต่มันจะทำให้ฟังก์ชั่นการแสดงความสามารถนี้ยอดเยี่ยมเป็นสองเท่าarray_filter_assocหากมีฟังก์ชั่นดังกล่าว

  • หากคุณไม่ใช้องค์ประกอบที่สอง ( 1 => ...) ( ส่วนของมูลค่า ) ในการติดต่อกลับnullจะใช้แทนค่าจริง

  • องค์ประกอบอื่นใดยกเว้นองค์ประกอบที่มีคีย์0และ1ในการติดต่อกลับจะถูกละเว้น

  • และในที่สุดถ้าแลมบ์ดาคืนค่าใด ๆ ยกเว้นnullหรืออาเรย์มันจะถือว่าเสมือนว่าทั้งค่าและคีย์ถูกละไว้ดังนั้น:

    1. มีการกำหนดคีย์ใหม่สำหรับองค์ประกอบ
    2. null ใช้เป็นค่าของมัน
คำเตือน:
โปรดจำไว้ว่าฟีเจอร์สุดท้ายนี้เป็นเพียงส่วนที่เหลือของฟีเจอร์ก่อนหน้าและอาจไม่มีประโยชน์อย่างสมบูรณ์ การใช้งานฟีเจอร์นี้ไม่ได้รับการสนับสนุนอย่างมากเนื่องจากฟีเจอร์นี้จะถูกคัดค้านและเปลี่ยนแปลงโดยไม่คาดคิดในรุ่นอนาคต

หมายเหตุ:
ในซึ่งแตกต่างจากarray_mapทุกพารามิเตอร์ที่ไม่ใช่อาร์เรย์ส่งผ่านไปยังarray_map_assocมีข้อยกเว้นของพารามิเตอร์โทรกลับครั้งแรกที่มีการออกเสียงเงียบอาร์เรย์

ตัวอย่าง:
// TODO: examples, anyone?

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.