当前位置: 首页 > news >正文

C#基础--特殊的集合

文章目录

  • 特殊的集合
    • BitArray 类
    • BitVector32 结构
    • 可观察的集合
    • 不变的集合
    • 并发集合

特殊的集合

BitArray 类

BitArray类是一个引用类型,它包含一个int数组,其中每32位使用一个新整数。
在这里插入图片描述

public static class BitArrayExtensions
{
    public static string GetBitsFormat(this BitArray bits)
    {
        var sb = new StringBuilder();
        for (int i = bits.Length - 1; i >= 0; i--)
        {
            sb.Append(bits[i] ? 1 : 0);
            if (i != 0 && i % 4 == 0)
            {
                sb.Append("_");
            }
        }

        return sb.ToString();
    }
}

class Program
{
    static void Main()
    {
        var bits1 = new BitArray(9);
        bits1.SetAll(true);
        bits1.Set(1, false);
        bits1[5] = false;
        bits1[7] = false;
        Console.Write("initialized: ");
        Console.WriteLine(bits1.GetBitsFormat());

        Console.Write("not ");
        Console.Write(bits1.GetBitsFormat());
        bits1.Not();
        Console.Write(" = ");
        Console.WriteLine(bits1.GetBitsFormat());

        var bits2 = new BitArray(bits1);
        bits2[0] = true;
        bits2[1] = false;
        bits2[4] = true;
        Console.Write($"{bits1.GetBitsFormat()} OR {bits2.GetBitsFormat()}");
        Console.Write(" = ");
        bits1.Or(bits2);
        Console.WriteLine(bits1.GetBitsFormat());

        Console.Write($"{bits2.GetBitsFormat()} AND {bits1.GetBitsFormat()}");
        Console.Write(" = ");
        bits2.And(bits1);
        Console.WriteLine(bits2.GetBitsFormat());

        Console.Write($"{bits1.GetBitsFormat()} XOR {bits2.GetBitsFormat()}");
        bits1.Xor(bits2);
        Console.Write(" = ");
        Console.WriteLine(bits1.GetBitsFormat());

        Console.ReadLine();
    }
}

BitVector32 结构

如果事先知道需要的位数,就可以使用BitVector32结构替代BitArray类。BitVector32结构效率较高,因为 它是一个值类型,在整数栈上存储位。一个整数可以存储32位。如果需要更多的位,就可以使用多个BitVector32 值或BitArray类。BitArray类可以根据需要增大,但BitVector32结构不能。
在这里插入图片描述

public static class BinaryExtensions
{
    public static string AddSeparators(this string number) =>
        number.Length <= 4 ? number :
            string.Join("_",
                Enumerable.Range(0, number.Length / 4)
                    .Select(i => number.Substring(startIndex: i * 4, length: 4)).ToArray());

    public static string ToBinaryString(this int number) =>
        Convert.ToString(number, toBase: 2).AddSeparators();
}


class Program
{
    static void Main()
    {
        // create a mask using the CreateMask method
        var bits1 = new BitVector32();
        int bit1 = BitVector32.CreateMask();
        int bit2 = BitVector32.CreateMask(bit1);
        int bit3 = BitVector32.CreateMask(bit2);
        int bit4 = BitVector32.CreateMask(bit3);
        int bit5 = BitVector32.CreateMask(bit4);

        bits1[bit1] = true;
        bits1[bit2] = false;
        bits1[bit3] = true;
        bits1[bit4] = true;
        bits1[bit5] = true;
        Console.WriteLine(bits1);

        // create a mask using an indexer
        bits1[0xab_cdef] = true;
        Console.WriteLine();

        int received = 0x79ab_cdef;

        BitVector32 bits2 = new BitVector32(received);
        Console.WriteLine(bits2);

        // sections: FF EEE DDD CCCC BBBBBBBB
        // AAAAAAAAAAAA
        BitVector32.Section sectionA = BitVector32.CreateSection(0xfff);
        BitVector32.Section sectionB = BitVector32.CreateSection(0xff, sectionA);
        BitVector32.Section sectionC = BitVector32.CreateSection(0xf, sectionB);
        BitVector32.Section sectionD = BitVector32.CreateSection(0x7, sectionC);
        BitVector32.Section sectionE = BitVector32.CreateSection(0x7, sectionD);
        BitVector32.Section sectionF = BitVector32.CreateSection(0x3, sectionE);

        Console.WriteLine($"Section A: {bits2[sectionA].ToBinaryString()}");
        Console.WriteLine($"Section B: {bits2[sectionB].ToBinaryString()}");
        Console.WriteLine($"Section C: {bits2[sectionC].ToBinaryString()}");
        Console.WriteLine($"Section D: {bits2[sectionD].ToBinaryString()}");
        Console.WriteLine($"Section E: {bits2[sectionE].ToBinaryString()}");
        Console.WriteLine($"Section F: {bits2[sectionF].ToBinaryString()}");

        Console.ReadLine();
    }
}

可观察的集合

如果需要集合中的元素何时删除或添加的信息,就可以使用ObservableCollectionO类。这个类最初是为
WPF定义的,这样UI就可以得知集合的变化,通用Windows应用程序使用它的方式相同。这个类的名称空间 是System.Collections. ObjectModeloObservableCollection类派生自Collection基类,该基类可用于创建自定义集合,并在内部使用Ust 类。重写基类中的虚方法SetltonO和RemoveltonO*以触发CollectionChanged事件。这个类的用户可以使用 INotifyCollectionChanged 接口注册这个事件。

class Program
{
    static void Main()
    {
        var data = new ObservableCollection<string>();
        
        data.CollectionChanged += Data_CollectionChanged;
        data.Add("One");
        data.Add("Two");
        data.Insert(1, "Three");
        data.Remove("One");

        data.CollectionChanged -= Data_CollectionChanged;

        Console.ReadLine();
    }

    public static void Data_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Console.WriteLine($"action: {e.Action.ToString()}");

        if (e.OldItems != null)
        {
            Console.WriteLine($"starting index for old item(s): {e.OldStartingIndex}");
            Console.WriteLine("old item(s):");
            foreach (var item in e.OldItems)
            {
                Console.WriteLine(item);
            }
        }
        if (e.NewItems != null)
        {
            Console.WriteLine($"starting index for new item(s): {e.NewStartingIndex}");
            Console.WriteLine("new item(s): ");
            foreach (var item in e.NewItems)
            {
                Console.WriteLine(item);
            }
        }
        Console.WriteLine();
    }
}

不变的集合

如果对象可以改变其状态,就很难在多个同时运行的任务中使用。这些集合必须同步。如果对象不能改变 其状态,就很容易在多个线程中使用。不能改变的对象称为不变的对象。不能改变的集合称为不变的集合。

public class Account
{
    public Account(string name, decimal amount)
    {
        Name = name;
        Amount = amount;
    }
    public string Name { get; }
    public decimal Amount { get; }
}

class Program
{
    static void Main()
    {
        SimpleArrayDemo();
        ImmutableList<Account> accounts = CreateImmutableList();
        UsingABuilder(accounts);
        LinqDemo();

        Console.ReadLine();
    }

    public static void LinqDemo()
    {
        ImmutableArray<string> arr = ImmutableArray.Create<string>("one", "two", "three", "four", "five");
        var result = arr.Where(s => s.StartsWith("t"));
    }

    public static void UsingABuilder(ImmutableList<Account> immutableAccounts)
    {
        ImmutableList<Account>.Builder builder = immutableAccounts.ToBuilder();
        for (int i = 0; i < builder.Count; i++)
        {
            Account a = builder[i];
            if (a.Amount > 0)
            {
                builder.Remove(a);
            }
        }

        ImmutableList<Account> overdrawnAccounts = builder.ToImmutable();

        overdrawnAccounts.ForEach(a => Console.WriteLine($"{a.Name} {a.Amount}"));
    }

    public static ImmutableList<Account> CreateImmutableList()
    {
        var accounts = new List<Account>() {
            new Account("Scrooge McDuck", 667377678765m),
            new Account("Donald Duck", -200m),
            new Account("Ludwig von Drake", 20000m)
        };

        ImmutableList<Account> immutableAccounts = accounts.ToImmutableList();

        foreach (var account in immutableAccounts)
        {
            Console.WriteLine($"{account.Name} {account.Amount}");
        }

        immutableAccounts.ForEach(a => Console.WriteLine($"{a.Name} {a.Amount}"));

        return immutableAccounts;
    }

    public static void SimpleArrayDemo()
    {
        ImmutableArray<string> a1 = ImmutableArray.Create<string>();
        ImmutableArray<string> a2 = a1.Add("Williams");
        ImmutableArray<string> a3 =
            a2.Add("Ferrari").Add("Mercedes").Add("Red Bull Racing");
    }
}

并发集合

不变的集合很容易在多个线程中使用,因为它们不能改变。如果希望使用应在多个线程中改变的集合,.NET 在名称空间System.Collections.Concurrent中提供了几个线程安全的集合类。线程安全的集合可防止多个线程以 相互冲突的方式访问集合。
为了对集合进行线程安全的访问,定义了 IProducerConsumerCollection接口。这个接口中最重要的方法是 TryAdd()和TryTake()。TryAdd()方法尝试给集合添加一项,但如果集合禁止添加项,这个操作就可能失败。为了给 出相关信息,TiyAdd()方法返回一个布尔值,以说明操作是成功还是失败。TryTake()方法也以这种方式工作,以通 知调用者操作是成功还是失败,并在操作成功时返回集合中的项。

public class ColoredConsole
{
    private static object syncOutput = new object();
    public static void WriteLine(string message)
    {
        lock (syncOutput)
        {
            Console.WriteLine(message);
        }
    }
    public static void WriteLine(string message, string color)
    {
        lock (syncOutput)
        {
            Console.ForegroundColor = (ConsoleColor)Enum.Parse(
                typeof(ConsoleColor), color);
            Console.WriteLine(message);
            Console.ResetColor();
        }
    }
}

public class Info
{
    public Info(string word, int count)
    {
        Word = word;
        Count = count;
    }

    public string Word { get; }
    public int Count { get; }
    public string Color { get; set; }

    public override string ToString() => $"{Count} times: {Word}";
}

public static class PipelineStages
{
    public static Task ReadFilenamesAsync(string path, BlockingCollection<string> output)
    {
        return Task.Factory.StartNew(() =>
        {
            foreach (string filename in Directory.EnumerateFiles(path, "*.cs",
                SearchOption.AllDirectories))
            {
                output.Add(filename);
                ColoredConsole.WriteLine($"stage 1: added {filename}");
            }
            output.CompleteAdding();
        }, TaskCreationOptions.LongRunning);
    }

    public static async Task LoadContentAsync(BlockingCollection<string> input, BlockingCollection<string> output)
    {
        foreach (var filename in input.GetConsumingEnumerable())
        {
            using (FileStream stream = File.OpenRead(filename))
            {
                var reader = new StreamReader(stream);
                string line = null;
                while ((line = await reader.ReadLineAsync()) != null)
                {
                    output.Add(line);
                    ColoredConsole.WriteLine($"stage 2: added {line}");
                    await Task.Delay(20);
                }
            }
        }
        output.CompleteAdding();
    }

    public static Task ProcessContentAsync(BlockingCollection<string> input,  ConcurrentDictionary<string, int> output)
    {
        return Task.Factory.StartNew(() =>
        {
            foreach (var line in input.GetConsumingEnumerable())
            {
                string[] words = line.Split(' ', ';', '\t', '{', '}', '(', ')',
                    ':', ',', '"');
                foreach (var word in words.Where(w => !string.IsNullOrEmpty(w)))
                {
                    output.AddOrUpdate(key: word, addValue: 1, updateValueFactory: (s, i) => ++i);
                    ColoredConsole.WriteLine($"stage 3: added {word}");
                }
            }
        }, TaskCreationOptions.LongRunning);
    }

    public static Task TransferContentAsync(ConcurrentDictionary<string, int> input, BlockingCollection<Info> output)
    {
        return Task.Factory.StartNew(() =>
        {
            foreach (var word in input.Keys)
            {
                if (input.TryGetValue(word, out int value))
                {
                    var info = new Info(word, value);
                    output.Add(info);
                    ColoredConsole.WriteLine($"stage 4: added {info}");
                }
            }
            output.CompleteAdding();
        }, TaskCreationOptions.LongRunning);
    }

    public static Task AddColorAsync(BlockingCollection<Info> input, BlockingCollection<Info> output)
    {
        return Task.Factory.StartNew(() =>
        {
            foreach (var item in input.GetConsumingEnumerable())
            {
                if (item.Count > 40)
                {
                    item.Color = "Red";
                }
                else if (item.Count > 20)
                {
                    item.Color = "Yellow";
                }
                else
                {
                    item.Color = "Green";
                }
                output.Add(item);
                ColoredConsole.WriteLine($"stage 5: added color {item.Color} to {item}");
            }
            output.CompleteAdding();
        }, TaskCreationOptions.LongRunning);
    }

    public static Task ShowContentAsync(BlockingCollection<Info> input)
    {
        return Task.Factory.StartNew(() =>
        {
            foreach (var item in input.GetConsumingEnumerable())
            {
                ColoredConsole.WriteLine($"stage 6: {item}", item.Color);
            }
        }, TaskCreationOptions.LongRunning);
    }
}
class Program
{
    static void Main()
    {
        StartPipelineAsync().Wait();
        Console.ReadLine();
    }

    public static async Task StartPipelineAsync()
    {
        var fileNames = new BlockingCollection<string>();
        var lines = new BlockingCollection<string>();
        var words = new ConcurrentDictionary<string, int>();
        var items = new BlockingCollection<Info>();
        var coloredItems = new BlockingCollection<Info>();
        Task t1 = PipelineStages.ReadFilenamesAsync(@"../..", fileNames);
        ColoredConsole.WriteLine("started stage 1");
        Task t2 = PipelineStages.LoadContentAsync(fileNames, lines);
        ColoredConsole.WriteLine("started stage 2");
        Task t3 = PipelineStages.ProcessContentAsync(lines, words);
        await Task.WhenAll(t1, t2, t3);
        ColoredConsole.WriteLine("stages 1, 2, 3 completed");
        Task t4 = PipelineStages.TransferContentAsync(words, items);
        Task t5 = PipelineStages.AddColorAsync(items, coloredItems);
        Task t6 = PipelineStages.ShowContentAsync(coloredItems);
        ColoredConsole.WriteLine("stages 4, 5, 6 started");

        await Task.WhenAll(t4, t5, t6);
        ColoredConsole.WriteLine("all stages finished");
    }
}

相关文章:

  • 吴恩达2022机器学习_第二部分高级学习算法笔记
  • DGL教程
  • FAST-LIO2代码解析(五)
  • 苦卷28天,阿里P8给我的Alibaba面试手册,终于成功踹开字节大门
  • Vue:v-on、v-bind、v-model、@click、:model用法以及区别(附代码实例)
  • 手写Sping IOC(基于Setter方法注入)
  • 一、SpringBoot前置(从0搭建Maven项目)
  • 宝藏教程:超详细一条龙教程!从零搭建React项目全家桶
  • 网络编程学习总结3
  • 欧姆龙CP1H如何进行PLC远程编程及数据采集
  • CSGO Bway电竞ETERNAL FIRE可以参加BLAST FALL,但MOUZ却错过了
  • 收获tips
  • Vue3+elementplus搭建通用管理系统实例十二:使用通用表格、表单实现对应功能
  • 抖音根据关键词取视频列表 API 返回值说明
  • 120页7万字XX云数据中心解决方案技术方案
  • 2018以太坊智能合约编程语言solidity的最佳IDEs
  • go append函数以及写入
  • Linux下的乱码问题
  • Shell编程
  • Swoft 源码剖析 - 代码自动更新机制
  • VirtualBox 安装过程中出现 Running VMs found 错误的解决过程
  • 基于 Ueditor 的现代化编辑器 Neditor 1.5.4 发布
  • 普通函数和构造函数的区别
  • 容器服务kubernetes弹性伸缩高级用法
  • 如何正确配置 Ubuntu 14.04 服务器?
  • 少走弯路,给Java 1~5 年程序员的建议
  • 思否第一天
  • 提升用户体验的利器——使用Vue-Occupy实现占位效果
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • d²y/dx²; 偏导数问题 请问f1 f2是什么意思
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • ​secrets --- 生成管理密码的安全随机数​
  • ​二进制运算符:(与运算)、|(或运算)、~(取反运算)、^(异或运算)、位移运算符​
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • (3)nginx 配置(nginx.conf)
  • (9)YOLO-Pose:使用对象关键点相似性损失增强多人姿态估计的增强版YOLO
  • (附源码)ssm经济信息门户网站 毕业设计 141634
  • (全注解开发)学习Spring-MVC的第三天
  • (转)Linq学习笔记
  • ./configure,make,make install的作用
  • .NET Core 成都线下面基会拉开序幕
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .NET6 命令行启动及发布单个Exe文件
  • .net打印*三角形
  • .NET设计模式(11):组合模式(Composite Pattern)
  • /etc/fstab 只读无法修改的解决办法
  • @Autowired多个相同类型bean装配问题
  • @RequestMapping 的作用是什么?
  • [ linux ] linux 命令英文全称及解释
  • [20190416]完善shared latch测试脚本2.txt
  • [202209]mysql8.0 双主集群搭建 亲测可用
  • [2023-年度总结]凡是过往,皆为序章
  • [AIGC] Spring Interceptor 拦截器详解
  • [BZOJ1877][SDOI2009]晨跑[最大流+费用流]