question

MarkusFreitag-0088 avatar image
0 Votes"
MarkusFreitag-0088 asked ChristopherBradford-2324 answered

C# Two lists to one list, LinQ

Hello,
I have two lists and need a list as result. Is there a way to solve this with LinQ?
If so, how?
44560--onelist.png



My attempts, it would be better maybe to load it into a dictionary, but how?


 HashSet<Tuple<string, bool>> hsResultList = new HashSet<Tuple<string, bool>>();
    
  for (int side = 0; side <= 2; side++)   // Side 1 and Side 2
  {
    
  foreach (var sB in CurrentPanel.ListSides[(int)side - 1].Boards )
  {
  var qryAlreadyInside = hsResultList.Where(x => x.Item1.Contains(sB.Index)).FirstOrDefault();
  if ( qryAlreadyInside  == null )
  hsResultList.Add(new Tuple<string, bool>(sB.Index, sB.Badmark));


If the status is false in one list, the entire status must be false in the merged dictionary.

 var dicSide1 = CurrentPanel.ListSides[0].ListSingleBoards.ToDictionary(x => x.Index, v => v.State);
 var dicSide2 = CurrentPanel.ListSides[1].ListSingleBoards.ToDictionary(x => x.Index, v => v.State);
 var dicResultSide1Side2Badmarks = dicSide1.Union(dicSide2.Where(k => !dicSide1.ContainsKey(k.Key))).ToDictionary(k => k.Key, v => v.Value);
    
 int badBoards = dicResultSide1Side2Badmarks.Where(x => x.Value == false).Count();
 int goodBoards = dicResultSide1Side2Badmarks.Where(x => x.Value == true).Count();






dotnet-csharp
-onelist.png (18.8 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

TimonYang-MSFT avatar image
1 Vote"
TimonYang-MSFT answered MarkusFreitag-0088 edited

You can also consider this method, merge them, and then group them to determine whether there is false in each group:

         public static void Main()
         {
             List<A> list1 = new List<A>() {
             new A(){ Index = 1, State = false },
             new A(){ Index = 2, State = false },
             new A(){ Index = 3, State = true },
             new A(){ Index = 4, State = false },
             new A(){ Index = 5, State = false },
         };
             List<A> list2 = new List<A>() {
             new A(){ Index = 1, State = false },
             new A(){ Index = 2, State = true },
             new A(){ Index = 3, State = true },
             new A(){ Index = 4, State = false },
             new A(){ Index = 5, State = false },
             new A(){ Index = 6, State = true },
             new A(){ Index = 7, State = false },
         };
             var list = list1.Concat(list2);
    
             var re = from a in list
                      group a by a.Index into g
                      select new
                      {
                          Key = g.Key,
                          Value = g.Where(x => x.State == false).Count() > 0 ? false : true
                      };
             Dictionary<int, bool> dict1 = re.ToDictionary(x => x.Key, y => y.Value);
         }

45004-1.png


If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



1.png (4.6 KiB)
· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks too, looks good.

G9xSCu




I have all possibilities here. Do you know if I can set a breakpoint at the dotnetfiddle?


Can I write the query like this?
//var qry = list.GroupBy(x => x.Index).Select(y => y.Key, z =>

             var list = list1.Concat(list2);
    
             var re = from a in list
                      group a by a.Index into g
                      select new
                      {
                          Key = g.Key,
                          Value = g.Where(x => x.State == true).Count() > 0 ? true : false
                      };
             //var qry = list.GroupBy(x => x.Index).Select(y => y.Key, z => z.v)))
    
             Dictionary<int, bool> dict1 = re.ToDictionary(x => x.Key, y => y.Value);
0 Votes 0 ·

@MarkusFreitag-0088
The code can be written like this:
var re1 = list.GroupBy(a => a.Index).Select((g, index) => new { g.Key, Value = g.Where(x => x.State == false).Count() > 0 ? false : true });
I noticed that you modified Value = xxx in the code. Now as long as there is true in the group, the corresponding Value in the result is true, which seems to be contrary to your original description.
Did the requirements change, or was it accidentally wrong?
By the way, I don't know how to add a breakpoint in that website, I haven't used it.


1 Vote 1 ·


Did the requirements change, or was it accidentally wrong?

I wanted to test in case the requirement of the check should be changed. So I have all possibilities. Thanks a lot.

0 Votes 0 ·
cheong00 avatar image
2 Votes"
cheong00 answered cheong00 commented

My take on this with LINQ: https://dotnetfiddle.net/RlLMHU

· 5
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Ok, thanks, but looks complicated. Is there a solution with Dictionary? Can you explain anything else about it?

0 Votes 0 ·
cheong00 avatar image cheong00 MarkusFreitag-0088 ·

LINQ syntax do not offer "full join" directly, so you have to do left join then right join and use .Union() to combine them.

Modified a bit to change to Dictionary<int, A>: https://dotnetfiddle.net/TexkOH

1 Vote 1 ·

OK, your solution is to create a left and a right result list first. Then a merged result list with union. Right?


Sample aj8MEk



OK, if I need to check with true, I can go this way, with | instead &, right?

 var left = (from l1 in dicSide1
  join l2 in dicSide2 on l1.Key equals l2.Key into j
  from l2 in j.DefaultIfEmpty()
  select new Dictionary<string, bool>()
  {  
      Keys = l1.Key,
      Value = l1.Value | (l2.Key == null ? false : l2.Value)
  }
   );

Can we use for all a dictionary?





0 Votes 0 ·
Show more comments
JaliyaUdagedara avatar image
0 Votes"
JaliyaUdagedara answered

May be something simple,

 var list1 = new List<A>()
 {
     new A(){ Index = 1, State = false },
     new A(){ Index = 2, State = false },
     new A(){ Index = 3, State = true },
     new A(){ Index = 4, State = false },
     new A(){ Index = 5, State = false },
 };
    
 var list2 = new List<A>()
 {
     new A(){ Index = 1, State = false },
     new A(){ Index = 2, State = true },
     new A(){ Index = 3, State = false },
     new A(){ Index = 4, State = false },
     new A(){ Index = 5, State = false },
     new A(){ Index = 6, State = true },
     new A(){ Index = 7, State = false },
 };
    
 List<A> leftList = list2;
 List<A> rightList = list1;
 if (list1.Count > list2.Count)
 {
     leftList = list1;
     rightList = list2;
 }
    
 IEnumerable<A> finalList = leftList
     .Select(x =>
     {
         var matchingState = rightList.SingleOrDefault(y => y.Index == x.Index)?.State;
         var finalState = matchingState == null ? x.State : matchingState.Value && x.State;
    
         return new A
         {
             Index = x.Index,
             State = finalState
         };
     });

Output:

 1 False
 2 False
 3 False
 4 False
 5 False
 6 True
 7 False
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

jjnguy avatar image
1 Vote"
jjnguy answered jjnguy edited

I'd do something like this:

 using System;
 using System.Collections.Generic;
 using System.Linq;
    
 namespace scratch
 {
     class Program
     {
         static void Main(string[] args)
         {
             var listOne = new List<bool> { true, false, true, false, true, false, true, true };
             var listTwo = new List<bool> { false, true, true };
             var result = Merge(listOne, listTwo);
         }
    
         static List<bool> Merge(List<bool> one, List<bool> two)
         {
             var longer = one.Count > two.Count ? one : two;
             var shorter = one.Count > two.Count ? two : one;
             return longer
                 .Select((item, ix) => ix >= shorter.Count ? item : item && shorter[ix])
                 .ToList();
         }
     }
 }

The merge method takes in two lists. First it finds the longer of the two, and does a logical AND on the two values or just takes the remaining values.

I don't think there is much reason to load these into a Dictionary first since you can always get values out of a arrays by index in constant time.

An extra concise version might look like this:

 static List<bool> Merge2(List<bool> one, List<bool> two)
 {
     return Enumerable.Range(0, Math.Max(one.Count, two.Count))
         .Select(ix =>
             (ix >= one.Count || one[ix])
             &&
             (ix >= two.Count || two[ix]))
         .ToList();
 }

It does the same as above - but is a one-liner.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

ChristopherBradford-2324 avatar image
0 Votes"
ChristopherBradford-2324 answered

Another option:

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using Newtonsoft.Json;
    
 public class Program
 {
     public static void Main()
     {
         var first = new List<Item>{new Item(1,false), new Item(2, false), new Item(3,true), new Item(4,false), new Item(5,false)};
         var second = new List<Item>{new Item(1,false), new Item(2,true), new Item(3,false), new Item(4,false), new Item(5,false), new Item(6,true), new Item(7,false)};

         // Pure LINQ
         var result = second.Zip(first, (firstItem, secondItem) => new Item(firstItem.Index,  firstItem.State && secondItem.State)).Concat(second.Skip(first.Count));

         Console.WriteLine(JsonConvert.SerializeObject(result));
     }
        
     private record Item(int Index, bool State);
 }

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.