List.map每次都会分配一个新的List吗?

时间:2016-06-05 11:48:29

标签: f#

让我们考虑以下列表:

// 2 2 2 1 1 1
let xs = [2;2;2;1;1;1]

// 2 2 2 1 1 1
let xs' = List.map (fun x -> x) list

// 4 4 4 1 1 1
let xs'' = List.map (fun x -> x * x) list

List.map会在第二种情况下分配新列表吗?在第三种情况下,xs会与[1;1;1]共享尾部xs''吗?

2 个答案:

答案 0 :(得分:5)

标准库倾向于使用此类函数的简单实现。

因此,这种类型的优化没有完成。

可以在此处找到实施:https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/local.fs#L85

答案 1 :(得分:2)

正如John指出的那样,你提到的优化没有被执行。如果你真的需要它(这是非常不可能的),你可以编写自己的地图版本,它共享列表的尾部,如:

<!DOCTYPE html>
<html>
    <head>
        <link rel="stylesheet" type="text/css" href="table-styles.css">
        <title>Register</title>
    </head>
    <body>
        <form method='post' onsubmit="return confirm('Are you sure you want to submit?');">
            <table id='table-left'>
                <caption>11/22/33</caption>
                <caption>ROUTS</caption>
                <tr>
                    <th>ID</th>
                    <th>Date</th>
                    <th>Day</th>
                    <th>Month</th>
                    <th>Year</th>
                    <th>Arrival</th>
                    <th>Departure</th>
                    <th>S/N</th>
                    <th>Time Mark</th>
                    <th>Observation</th>
                </tr>
                <tr>
                    <td name="id-1">1</td> <!-- The value of this <td> tag needs to populate in the name of each next <td> 'name' parameter for this row!-->
                    <td name="ddate-1">03062016</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="day-1">Day</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="month-1">Month</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="year-1">Year</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="arrival-1">Arrival</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="departure-1">Departure</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="sn-1">S/N</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="time-mark-1">Time Mark</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                    <td name="observation-1">Observation</td> <!-- Here I want to add this number "1" to the name of the <td> element.-->
                </tr>
                <tr>
                    <td name="id-2">2</td> <!-- The value of this <td> tag needs to populate in the name of each next <td> 'name' parameter for this row!-->
                    <td name="ddate-2">03062016</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="day-2">Day</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="month-2">Month</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="year-2">Year</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="arrival-2">Arrival</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="departure-2">Departure</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="sn-2">S/N</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="time-mark-2">Time Mark</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                    <td name="observation-2">Observation</td> <!-- Here I want to add this number "2" to the name of the <td> element.-->
                </tr>
                <tr>
                    <td name="id-3">3</td> <!-- The value of this <td> tag needs to populate in the name of each next <td> 'name' parameter for this row!-->
                    <td name="ddate-3">03062016</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="day-3">Day</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="month-3">Month</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="year-3">Year</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="arrival-3">Arrival</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="departure-3">Departure</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="sn-3">S/N</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="time-mark-3">Time Mark</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                    <td name="observation-3">Observation</td> <!-- Here I want to add this number "3" to the name of the <td> element.-->
                </tr>
                <tr>
                    <td><input class='hdl' type='text' name='id' value=''></input></td>
                    <td><input class='hdl' type='text' name='date' value=''></input></td>
                    <td><input class='hds' type='text' name='day' value=''></input></td>
                    <td><input class='rm' type='text' name='month' value=''></input></td>
                    <td><input class='hm' type='text' name='year' value=''></input></td>
                    <td><input class='ob' type='text' name='arr' value=''></input></td>
                    <td><input class='pre' type='text' name='dep' value=''></input></td>
                    <td><input class='prs' type='text' name='sn' value=''></input></td>
                    <td><input class='vol' type='text' name='tm' value=''></input></td>
                    <td><input class='obs' type='text' name='ob' value=''></input></td>
                </tr>
            </table>
            <input id='submit' type='submit' name='submit' value='Submit' />
        </form>
    </body>
</html>

请注意:

  • 此实现将执行更多内存分配,然后只使用/// Returns a copy of 'a' which shares a common suffix with 'b'. /// 'a' and 'b' must me of equal length. let shareSuffixWith (a : 'a list) (b : 'a list) : 'a list = let discardLastNElements (n: int) (li : 'a list) = List.take (li.Length - n) li let commonSuffix = let zippedLists = List.zip a b let lastDifferentElemIndex = List.tryFindIndexBack (fun (e1, e2) -> e1 <> e2) zippedLists match lastDifferentElemIndex with | None -> b | Some(index) -> List.skip (index+1) b let aPreffix = discardLastNElements commonSuffix.Length a aPreffix @ commonSuffix /// Maps elements of a list using a mapping and shares /// common tail between input list and the result. let mapAndShareSuffix (mapping :'T -> 'T) (li : 'T list) : 'T list = let resultOfMap = List.map mapping li shareSuffixWith resultOfMap li ,但在垃圾收集期间将释放部分内存。

  • F#列表不占用太多空间 - 每个元素只有指针大小的两倍,因此在大多数情况下通过共享尾部获得的内存量最小

  • 共享列表的尾部需要处理和GC时间

  • 上面的实现是次优的而不是惯用的