Home > Enterprise >  How to check duplicate values in a dictionary
How to check duplicate values in a dictionary

Time:09-17

Im having 5 users and 5 services. I must catch if more than one user(s) have same service. So I created a dictionary:

//JMBGS represents users ids

List<string> multipleJMBGs = new List<string>();
multipleJMBGs.Add(data.jMBG);
multipleJMBGs.Add(data.secondPersonJMBG);
multipleJMBGs.Add(data.thirdPersonJMBG);
multipleJMBGs.Add(data.fourthPersonJMBG);
multipleJMBGs.Add(data.fifthPersonJMBG);
multipleJMBGs.RemoveAll(x => string.IsNullOrEmpty(x));

//object Service has Id property, and I need to check if more than one user has the same service 
var serviceForClient = data?.Schedules[0]?.Service;
var serviceForFirstFamilyMember = data?.Schedules[1]?.Service;
var serviceForSecondFamilyMember = data?.Schedules[2]?.Service;
var serviceForThirdFamilyMember = data?.Schedules[3]?.Service;
var serviceForFourthFamilyMember = data?.Schedules[4]?.Service;

Dictionary<string, EmployeeTableDay.ServiceDTO> userService = new Dictionary<string, EmployeeTableDay.ServiceDTO>();

userService.Add(data.jMBG, serviceForClient);
userService.Add(data.secondPersonJMBG, serviceForFirstFamilyMember);
userService.Add(data.thirdPersonJMBG, serviceForSecondFamilyMember);
userService.Add(data.fourthPersonJMBG, serviceForThirdFamilyMember);
userService.Add(data.fifthPersonJMBG, serviceForFourthFamilyMember);

What I want to have as flag (true/false):

  1. different users can have different services
  2. different users can have same services
  3. same users, can not have same service
  4. same users can have multiple services

UPDATE #1:

List<string> multipleJMBGs = new List<string>();
multipleJMBGs.Add(data.jMBG);
multipleJMBGs.Add(data.secondPersonJMBG);
multipleJMBGs.Add(data.thirdPersonJMBG);
multipleJMBGs.Add(data.fourthPersonJMBG);
multipleJMBGs.Add(data.fifthPersonJMBG);
multipleJMBGs.RemoveAll(x => string.IsNullOrEmpty(x));

var countedSchedules = data?.Schedules?.Count();

var serviceIdForClient = 0;
var serviceIdForFirstFamilyMember = 0;
var serviceIdForSecondFamilyMember = 0;
var serviceIdForThirdFamilyMember = 0;
var serviceIdForFourthFamilyMember = 0;

List<int> servicesIds = new List<int>();

if(countedSchedules >= 1 && data?.Schedules[0]?.Service != null)
{
    serviceIdForClient = data.Schedules[0].Service.Id;
    servicesIds.Add(serviceIdForClient);
}
if (countedSchedules >= 2 && data?.Schedules[1]?.Service != null)
{
    serviceIdForFirstFamilyMember = data.Schedules[1].Service.Id;
    servicesIds.Add(serviceIdForFirstFamilyMember);
}
if (countedSchedules >= 3 && data?.Schedules[2]?.Service != null)
{
    serviceIdForSecondFamilyMember = data.Schedules[2].Service.Id;
    servicesIds.Add(serviceIdForSecondFamilyMember);
}
if (countedSchedules >= 4 && data?.Schedules[3]?.Service != null)
{
    serviceIdForThirdFamilyMember = data.Schedules[3].Service.Id;
    servicesIds.Add(serviceIdForThirdFamilyMember);
}
if (countedSchedules == 5 && data?.Schedules[4]?.Service != null)
{
    serviceIdForFourthFamilyMember = data.Schedules[4].Service.Id;
    servicesIds.Add(serviceIdForFourthFamilyMember);
}

servicesIds = servicesIds.Where(x => x > 0).ToList();


//because dictionary throws an exception
for (int i = 0; i < countedSchedules; i  )
{
    multipleJMBGs[i] = i   " _ "   multipleJMBGs[i];
}

//create dictionary from two lists
var dic = multipleJMBGs.Zip(servicesIds, (k, v) => new { k, v }).ToDictionary(x => x.k, x => x.v);


var duplicateServices = dic.GroupBy(x => x.Value).Where(x => x.Count() > 1)
                    .Select(x => new { ServiceId = x.Key, Users = x.ToList() });

var duplicateUsers = dic.GroupBy(x => x.Key.Substring(3,x.Key.Length-3)).Where(x => x.Count() > 1)
                    .Select(x => new { User = x.Key, Services = x.ToList() });


if(duplicateServices > 1 && duplicateUsers.Count > 1)
{
    //show a message that it ca't be proceeed further
}
else
{
    //continue
}

CodePudding user response:

You can group the services by Id to get information on duplicates:

var groups = data?.Schedules
    .Select((service, index) => (service, index))
    .GroupBy(x => x.service.Id);
foreach (var g in groups) {
    if (g.Count() == 1) {
        Console.WriteLine(
            $"Service Id {g.Key} exists once for user index {g.First().index}");
    } else {
        string indexes = String.Join(", ", g.Select(t => t.index.ToString()));
        Console.WriteLine(
            $"Service Id {g.Key} is shared by user indexes {indexes}");
    }
}

If you don't call multipleJMBGs.RemoveAll(...), then the indexes in the users list will match the indexes of the services. So you can easily get the JMBG assigned to a service.

var groups = data?.Schedules
    .Select((service, index) => (service, index))
    .GroupBy(x => x.service.Id);
foreach (var g in groups) {
    if (g.Count() == 1) { // Service is unique
        var service = g.First().service;
        int index = g.First().index;
        string user = multipleJMBGs[index];
        ...
    } else { // Services assigned to more than one user.
        var serviceId = g.Key;
        var service = g.First().service;
        foreach (var t in g) {
            int index = t.index;
            string user = multipleJMBGs[index];
            ...
        }
        ...
    }
}

CodePudding user response:

Purely answering the question on how to check for duplicates within your dictionary:

You could group the values of your dictionary and look for duplicates that way.

var containsDuplicates = userService.GroupBy(x => x.Value).Any(x => x.Count() > 1);

If you want to actually see which services are used multiple times by which users, create the following grouping:

var duplicateServices = userService.GroupBy(x => x.Value).Where(x => x.Count() > 1)
                                   .Select(x => new { Service = x.Key, Users = x.ToList() });

UPDATE #1:

You don't necessarily have to group up both of these lists if you just need to check if any of the two contain duplicates.

We could simply compare the total count of the lists with the count of the list when we remove all possible duplicates:

var duplicateServices = countedSchedules != data?.Schedules?.Distinct().Count();
var duplicateUsers = multipleJMBGs.Count() != multipleJMBGs.Distinct().Count();

UPDATE #2: Sounds like you want to join the two lists together and not necessarily convert it to a dictionary, what we want to do instead is create a new List so we can group that on the combination of the two properties.

var containsDuplicates = multipleJMBGs.Zip(serviceIds, (JMBG, serviceId) => new { JMBG, serviceId })
                                             .Where(x => !string.IsNullOrEmpty(x.JMBG) && x.serviceId > 0) // Filter AFTER zipping the two lists together
                                             .GroupBy(x => x).Any(x => x.Count() > 1);

Do be aware that you are removing elements in both lists, meaning that the order might not be correct. You could instead add a Where clause after you zip the lists like in the example above.

  • Related