c#扩展类_vs扩展开发「建议收藏」

c#扩展类_vs扩展开发「建议收藏」Enumerable.Aggregate扩展方法在System.Linq命名空间中…本文介绍使用Aggregate进行求和、byte数组异或、字符串拼装/逆序输出。并对Aggregate进行改进,实现间隔求和,进一步改进查重极限算法。

大家好,欢迎来到IT知识分享网。Enumerable.Aggregate 扩展方法在System.Linq命名空间中,是Enumerable类的第一个方法(按字母顺序排名),但确是Enumerable里面相对复杂的方法。
MSDN对它的说明是:对序列应用累加器函数。备注中还有一些说明,大意是这个方法比较复杂,一般情况下用Sum、Max、Min、Average就可以了。
看看下面的代码,有了Sum,谁还会用Aggregate呢!

        
public
 
static
 
void
 Test1()
        {
            

int
[] nums 
=
 
new
 
int
[] { 
1

2

3

4

5

6

7

8

9

10
};

            
int
 sum1 
=
 nums.Sum();
            

int
 sum2 
=
 nums.Aggregate((i,j)
=>
i
+
j);
        }

同是求和,Sum不再需要额外参数,而Aggregate确还要将一个lambda作为参数。因为用起来麻烦,操作太低级,Aggregate渐渐被大多人忽视了…
实际上Aggregate因为“低级”,功能确是很强大的,通过它可以简化很多聚合运算。

首先来看对Aggregate组装字符串的问题:

        
public
 
static
 
void
 Test2()
        {
            

string
[] words 
=
 
new
 
string
[] { 

Able



was



I



ere



I



saw



Elba

};
            

string
 s 
=
 words.Aggregate((a, n) 
=>
 a 
+
 

 

 
+
 n);
            Console.WriteLine(s);
        }

输出结果是:Able was I ere I saw Elba (注:出自《大国崛起》,狄娜最后讲述了拿破仑一句经典)。
当然考虑性能的话还是用StringBuilder吧,这里主要介绍用法。这个Sum做不到吧!

Aggregate还可以将所有字符串倒序累加,配合String.Reverse扩展可以实现整个句子的倒序输出:

c#扩展类_vs扩展开发「建议收藏」
        
public
 
static
 
void
 Test3()
c#扩展类_vs扩展开发「建议收藏」c#扩展类_vs扩展开发「建议收藏」        


{
c#扩展类_vs扩展开发「建议收藏」c#扩展类_vs扩展开发「建议收藏」            
string[] words = new string[] AblewasIereIsawElba};
c#扩展类_vs扩展开发「建议收藏」            
string normal = words.Aggregate((a, n) => a +   + n);
c#扩展类_vs扩展开发「建议收藏」            
string reverse = words.Aggregate((a, n) => n.Reverse() +   + a);
c#扩展类_vs扩展开发「建议收藏」
c#扩展类_vs扩展开发「建议收藏」            Console.WriteLine(
正常: + normal);
c#扩展类_vs扩展开发「建议收藏」            Console.WriteLine(
倒置: + reverse);
c#扩展类_vs扩展开发「建议收藏」        }


c#扩展类_vs扩展开发「建议收藏」        

//
 倒置字符串,输入”abcd123″,返回”321dcba”

c#扩展类_vs扩展开发「建议收藏」

        
public
 
static
 
string
 Reverse(
this
 
string
 value)
c#扩展类_vs扩展开发「建议收藏」c#扩展类_vs扩展开发「建议收藏」        


{
c#扩展类_vs扩展开发「建议收藏」            
char[] input = value.ToCharArray();
c#扩展类_vs扩展开发「建议收藏」            
char[] output = new char[value.Length];
c#扩展类_vs扩展开发「建议收藏」            
for (int i = 0; i < input.Length; i++)
c#扩展类_vs扩展开发「建议收藏」                output[input.Length 
 1  i] = input[i];
c#扩展类_vs扩展开发「建议收藏」            
return new string(output);
c#扩展类_vs扩展开发「建议收藏」        }

看下面,输出结果好像不太对:
c#扩展类_vs扩展开发「建议收藏」
怎么中间的都一样,两的单词首尾字母大小写发生转换了呢?!
仔细看看吧,不是算法有问题,是输入“有问题”。搜索一下“Able was I ere I saw Elba”,这可是很有名的英文句子噢!

Aggregate还可以实现异或(^)操作

        
public
 
static
 
void
 Test4()
        {
            

byte
[] data 
=
 
new
 
byte
[] { 
0x31

0x32

0x33

0x34

0x35
 };
            

byte
 checkSum 
=
 data.Aggregate((a, n) 
=>
 (
byte
)(a 
^
 n));
        }

对经常作串口通信的朋友比较实用。

看来Aggregate也是比较“简单易用”的,深入一步来看看它是怎么实现的吧,使用Reflector,反编译一下System.Core.dll。
以下代码取自反编译结果,为了演示删除了其中的空值判断代码:

c#扩展类_vs扩展开发「建议收藏」
c#扩展类_vs扩展开发「建议收藏」
Aggregate

也很简单吧,就是一个循环!前面lambda表达式中参数a, n 分别对应current, enumerator.Current,对照一下,还是很好理解的。

现在我们想求整数数组中位置为偶数的数的和(间隔求和),可以用Where配合Sum:

        
public
 
static
 
void
 Test5()
        {
            

int
[] nums 
=
 
new
 
int
[] { 
10

20

30

40

50
 };
            

int
 sum1 
=
 nums.Where((n, i) 
=>
 i 
%
 
2
 
==
 
0
).Sum();
//
10 + 30 + 50


        }

这个Where扩展设计的很好,它不但能带出某项的值“n”,还能带出项的位置“i”。
Aggregate可不行!我们来改进一下:

        
//
改进的Aggerate扩展(示例代码,实际使用请添加空值检查)


        
public
 
static
 TSource Aggregate
<
TSource
>
(
this
 IEnumerable
<
TSource
>
 source, Func
<
TSource, TSource, 
int
, TSource
>
 func)
        {
            

int
 index 
=
 
0
;
            

using
 (IEnumerator
<
TSource
>
 enumerator 
=
 source.GetEnumerator())
            {
                enumerator.MoveNext();
                index

++
;
                TSource current 

=
 enumerator.Current;
                

while
 (enumerator.MoveNext())
                    current 

=
 func(current, enumerator.Current, index
++
);
                

return
 current;
            }
        }

改进后的Aggregate更加强大,前面的求偶数位置数和的算法可以写成下面的样子:

        
public
 
static
 
void
 Test6()
        {
            

int
[] nums 
=
 
new
 
int
[] { 
10

20

30

40

50
 };
            

int
 sum2 
=
 nums.Aggregate((a, c, i) 
=>
 a 
+
 i
%
2
 
==
 
0
 
?
 c : 
0
 );
//
10 + 30 + 50


        }

可能不够简洁,但它一个函数代替了Where和Sum。所在位置“i“的引入给Aggregate带来了很多新的活力,也增加了它的应用范围!

我随笔《使用“初中知识”实现查找重复最优算法 + 最终极限算法》中最后提出的“最终极限算法”,用上这里改进的Aggregate扩展,也可以甩开Select和Sum,更加精简一步了: 

        
public
 
static
 
void
 Test7()
        {
            

//
1~n放在含有n+1个元素的数组中,只有唯一的一个元素值重复,最简算法找出重复的数


            
int
[] array 
=
 
new
 
int
[] { 
1

3

2

3

4

5
 };
            

//
原极限算法


            
int
 repeatedNum1 
=
 array.Select((i, j) 
=>
 i 

 j).Sum();
            

//最新极限算法


            int repeatedNum2 = array.Aggregate((a, n, i) => a + n 
 i);
        }

 

本人系列文章《
c#扩展方法奇思妙用》,敬请关注!
c#扩展类_vs扩展开发「建议收藏」

 

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/28059.html

(0)
上一篇 2023-10-02 17:15
下一篇 2023-10-14 16:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信