元组,列表,--操作符性能

来源:互联网 发布:淘宝指数排行榜 编辑:程序博客网 时间:2024/05/19 06:35

元组,列表,--操作符性能

The time for calculating the length of a list is proportional to the length of the list, as opposed totuple_size/1, byte_size/1, andbit_size/1, which all execute in constant time.

Normally you don't have to worry about the speed of length/1, because it is efficiently implemented in C. In time critical-code, though, you might want to avoid it if the input list could potentially be very long.

Some uses of length/1 can be replaced by matching. For instance, this code

foo(L) when length(L) >= 3 ->    ...

can be rewritten to

foo([_,_,_|_]=L) ->   ...

(One slight difference is that length(L) will fail if theL is an improper list, while the pattern in the second code fragment will accept an improper list.)

setelement/3 copies the tuple it modifies. Therefore, updating a tuple in a loop usingsetelement/3 will create a new copy of the tuple every time.

There is one exception to the rule that the tuple is copied. If the compiler clearly can see that destructively updating the tuple would give exactly the same result as if the tuple was copied, the call tosetelement/3 will be replaced with a special destructive setelement instruction. In the following code sequence

multiple_setelement(T0) ->    T1 = setelement(9, T0, bar),    T2 = setelement(7, T1, foobar),    setelement(5, T2, new_value).

the first setelement/3 call will copy the tuple and modify the ninth element. The two followingsetelement/3 calls will modify the tuple in place.

For the optimization to be applied, all of the followings conditions must be true:

  • The indices must be integer literals, not variables or expressions.
  • The indices must be given in descending order.
  • There must be no calls to other function in between the calls to setelement/3.
  • The tuple returned from one setelement/3 call must only be used in the subsequent call tosetelement/3.

If it is not possible to structure the code as in the multiple_setelement/1 example, the best way to modify multiple elements in a large tuple is to convert the tuple to a list, modify the list, and convert the list back to a tuple.

Note that the '--' operator has a complexity proportional to the product of the length of its operands, meaning that it will be very slow if both of its operands are long lists:

DO NOT

        HugeList1 -- HugeList2

Instead use the ordsets module:

DO

        HugeSet1 = ordsets:from_list(HugeList1),        HugeSet2 = ordsets:from_list(HugeList2),        ordsets:subtract(HugeSet1, HugeSet2)        

Obviously, that code will not work if the original order of the list is important. If the order of the list must be preserved, do like this:

DO

        Set = gb_sets:from_list(HugeList2),        [E || E <- HugeList1, not gb_sets:is_element(E, Set)]

Subtle note 1: This code behaves differently from '--' if the lists contain duplicate elements. (One occurrence of an element in HugeList2 will removeall occurrences in HugeList1.)

Subtle note 2: This code compares lists elements using the '==' operator, while '--' uses the '=:='. If that difference is important,sets can be used instead of gb_sets, but note thatsets:from_list/1 is much slower than gb_sets:from_list/1 for long lists.

Using the '--' operator to delete an element from a list is not a performance problem:

OK

        HugeList1 -- [Element]
原创粉丝点击