.net 通过匹配值删除记录

1u4esq0p  于 2022-12-24  发布在  .NET
关注(0)|答案(5)|浏览(125)

我有一个字典里面的值是以下面的格式存储的-

userID, empDetails

例如,

1234, 'empName,jobDesc,CardNumber,Type'

我得把这些信息和另一组信息进行比较-

  • 如果输入的userId存在于上述字典中,则从字典中删除此记录。
  • 如果输入的CardNumber存在于上述字典中(此处userId未知),则从字典中删除此记录。

第一个条件很简单,可以通过以下方式实现

dictionary.Remove(key)

但是我很困惑,我该如何实现第二个条件。

if(CardNumber.PresentinAboveDictionary)
then
Remove that record

我知道我们可以像这样比较key中的部分字符串,但是我想删除记录。Check if any part of a hashtable value contains certain string c#

sdnqo3pr

sdnqo3pr1#

假设字典中的雇佣详细信息是指定格式的字符串,则需要:
1.在字典中搜索值
1.解析/拆分值以获取卡号
1.检查卡号以查看它们是否与您正在检查的卡号匹配
1.出现匹配时返回键值对
1.在返回的键值对中删除键的条目
解决方案的示例代码:

var dictionary = new Dictionary<int, string>() { { 1, "empName,jobDesc,124124134,Type" } };
                
var cardNumber = 124124134;
var entry = dictionary.FirstOrDefault(x => DoEmploymentDetailsContainCardNumber(x.Value, cardNumber));

if (!entry.Equals(default(KeyValuePair<int, string>)))
{
    dictionary.Remove(entry.Key);
}

检查卡号是否存在于雇用详细信息中的方法:

private static bool DoEmploymentDetailsContainCardNumber(string empDetails, int cardNumber)
{
    var splitEmpDetails = empDetails.Split(',');
    var empDetailsCardNumber = splitEmpDetails[2];
    return empDetailsCardNumber == cardNumber.ToString();
}
omqzjyyz

omqzjyyz2#

可以使用强类型List代替Dictionary
1.使用Linq内置Remove方法
1.使用Parallel.ForEach,迭代列表并删除项目(注意,需要更多时间)
伪代码:

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using System.Collections;

namespace ConsoleApp4
{
    public class Employee
    {
        public Employee(int userID, string empDetails)
        {
            string[] props = empDetails.Split(new char[] { ',' }, StringSplitOptions.None);
            this.userID = userID;
            this.empName = props[0];
            this.jobDesc = props[1];
            this.CardNumber = props[2];
            this.Type = props[3];
        }

        public int userID { get; set; }
        public string empName { get; set; }
        public string jobDesc { get; set; }
        public string CardNumber { get; set; }
        public string Type { get; set; }
    }

    public class MyCustomList : List<Employee>
    {
        public void Add(int userID, string empDetails)
        {
            this.Add(new Employee(userID, empDetails));
        }

        public bool Remove(string CardNumber)
        {
            bool found = false ;
            Parallel.ForEach(this,
            (i, state) =>
            {
                if (i.CardNumber == CardNumber)
                {
                    this.Remove(i);
                    state.Break();
                }
            });
            return found;
        }

        public bool RemoveV2(string CardNumber)
        {
            bool found = false;
            if (this.Any(x => x.CardNumber == CardNumber))
            {
                this.Remove(this.Where(x => x.CardNumber == CardNumber).First());
                found = true;
            }
            return found;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var dict = new MyCustomList();//userID, empDetails list
            dict.Add(12341, "empName1,jobDesc,CardNumber1,Type");
            dict.Add(12342, "empName2,jobDesc,CardNumber2,Type");
            dict.Add(12343, "empName3,jobDesc,CardNumber3,Type");
            dict.Add(12344, "empName4,jobDesc,CardNumber4,Type");
            dict.Add(12345, "empName5,jobDesc,CardNumber5,Type");
            dict.Add(12346, "empName6,jobDesc,CardNumber6,Type");
            dict.Add(12347, "empName7,jobDesc,CardNumber7,Type");
            dict.Add(12348, "empName8,jobDesc,CardNumber8,Type");

            //remove CardNumber5
            dict.Remove("CardNumber5");
            Console.Write(dict);
        }
    }
}
vhipe2zx

vhipe2zx3#

你可以按照简单的方法通过使用一个循环来移除密钥。
这里我假设字典中没有值为-1的键。

int keyToRemove = -1;
foreach (var entry in dictionary)
{
    if (entry.Value.Contains(CardNumber))
    {
        keyToRemove = entry.Key;
        break;
    }
}

if (keyToRemove != -1)
{
    dictionary.Remove(keyToRemove);
}
elcex8rz

elcex8rz4#

这可能是矫枉过正,并没有为重复阅读整个数据集进行优化,但它比公认的解决方案要快得多。我对下面的解决方案进行了测试,结果如下:
1.生成了1,000,000个具有唯一ID和卡号的数据行(如果卡号不唯一,该解决方案也可以工作)
1.按ID随机删除10万条数据,按卡号随机删除10万条数据
1.生成剩余数据项的列表
整个过程耗时约75秒。
然后我尝试使用接受的答案重复步骤1)和2)-大约10分钟后,删除数据项的速度大约为7%。因此,我认为下面的解决方案对于这种类型的操作大约快了2个数量级。
可能有更好的双链表实现,但我对它们都不太熟悉。

namespace Question
{
    public class EmployeeCollection 
    {
        private readonly Dictionary<int, ListNode<EmployeeDetails>> _idDictionary = new();
        private readonly Dictionary<string, Dictionary<int, EmployeeDetails>> _cardNumberDictionary = new();
        private readonly LinkedList<EmployeeDetails> _list = new();

        public void AddEmployee(EmployeeDetails details)
        {
            var node = new ListNode<EmployeeDetails>(details);
            _list.AddToStart(node);
            _idDictionary.Add(details.Id, node);
            
            if(!_cardNumberDictionary.ContainsKey(details.CardNumber))
            {
                _cardNumberDictionary.Add(details.CardNumber, new Dictionary<int, EmployeeDetails>());
            }

            _cardNumberDictionary[details.CardNumber].Add(details.Id, details);
        }

        public void RemoveById(int id)
        {
            if (_idDictionary.TryGetValue(id, out var node))
            {
                _idDictionary.Remove(id);
                _list.Remove(node);
                var list = _cardNumberDictionary[node.Value.CardNumber];
                list.Remove(id);

                if(list.Count == 0)
                {
                    _cardNumberDictionary.Remove(node.Value.CardNumber);
                }
            }
        }

        public void RemoveByCardNumber(string cardNumber)
        {
            if (_cardNumberDictionary.TryGetValue(cardNumber, out var employees))
            {
                _cardNumberDictionary.Remove(cardNumber);

                foreach (var employee in employees)
                {
                    if (_idDictionary.TryGetValue(employee.Key, out var node))
                    {
                        _list.Remove(node);
                    }
                }
            }
        }

        public IEnumerable<EmployeeDetails> Employees => _list.GetAllValues();

        public EmployeeDetails? GetById(int id)
        {
            if(_idDictionary.ContainsKey(id))
            {
                return _idDictionary[id].Value;
            }

            return null;
        }
    }

    public class EmployeeDetails
    {
        public int Id { get; init; }
        public string Name { get; init; }
        public string JobDescription { get; init; }
        public string CardNumber { get; init; }
        public string Type { get; init; }

        public static EmployeeDetails FromData(int id, string details)
        {
            var parts = details.Split(',');

            return new EmployeeDetails
            {
                Id = id,
                Name = parts[0],
                JobDescription = parts[1],
                CardNumber = parts[2],
                Type = parts[3],
            };
        }
    }

    public class LinkedList<T>
    {
        public int Count { get; private set; }
        private ListNode<T>? Start { get; set; }
        private ListNode<T>? End { get; set; }
        public bool IsEmpty => Count == 0;

        public void AddToStart(ListNode<T> node)
        {
            ArgumentNullException.ThrowIfNull(nameof(node));
            node.Next = null;
            node.Previous = null;

            if (IsEmpty)
            {
                Start = End = node;
            }
            else
            {
                Start!.Previous = node;
                node.Next = Start;
                Start = node;
            }

            Count++;
        }

        public void Remove(ListNode<T> node)
        {
            if (node != Start)
            {
                node.Previous!.Next = node.Next;
            }

            else
            {
                Start = node.Next;
            }

            if (node != End)
            {
                node.Next!.Previous = node.Previous;
            }

            else
            {
                End = node.Previous;
            }

            Count--;
        }

        public IEnumerable<T> GetAllValues()
        {
            var counter = Start;

            while (counter != null)
            {
                yield return counter.Value;
                counter = counter.Next;
            }
        }
    }

    public class ListNode<T>
    {
        public T Value { get; }
        public ListNode<T>? Previous { get; set; }
        public ListNode<T>? Next { get; set; }

        public ListNode(T value)
        {
            Value = value;
        }
    }
}
t3psigkw

t3psigkw5#

你可以做这样的事情。

var recordsToRemove = dictionary.Where(x => x.Value.Contains("what you are looking for"))
                                .ToList();

        if (recordsToRemove.Any())
        {
            foreach (var record in recordsToRemove)
            {
                dictionary.Remove(record.Key);
            }
        }

相关问题