Related
I have 2 List<string>s that contain a list of network names.
List<string> nets1 = new List<string>() { "net1", "net2", "net3" };
List<string> nets2 = new List<string>() { "net2", "net3", "net4" };
I want to combine them into a new List<string>, but only where the strings are equal. So my desired result will be of type List<string> and contain ONLY net2 and net3.
I have tried to use Union and Concat but they dont seem to be what I am looking for
What you are looking for is Intersect:
var list = list1.Intersect(list2).ToList();
Hope you are looking for the common elements in both list, you can use Intersect
var commonElements = nets1.Intersect(nets2).ToList();
I tried looking through some of the other questions, but couldn't find any that did a partial match.
I have two List<string>
They have codes in them. One is a list of selected codes, one is a list of required codes. The entire code list is a tree though, so they have sub codes. An example would be
Code B
Code B.1
Code B.11
So lets say the Required code is B, but anything under it's tree will meet that requirement, so if the Selected codes are A and C the match would fail, but if one of the selected codes was B.1 it contains the partial match.
I just need to know if any of the selected codes partially match any of the required codes. Here is my current attempt at this.
//Required is List<string> and Selected is a List<string>
int count = (from c in Selected where c.Contains(Required.Any()) select c).Count();
The error I get is on the Required.Any() and it's cannot convert from bool to string.
Sorry if this is confusing, let me know if adding any additional information would help.
I think you need something like this:
using System;
using System.Collections.Generic;
using System.Linq;
static class Program {
static void Main(string[] args) {
List<string> selected = new List<string> { "A", "B", "B.1", "B.11", "C" };
List<string> required = new List<string> { "B", "C" };
var matching = from s in selected where required.Any(r => s.StartsWith(r)) select s;
foreach (string m in matching) {
Console.WriteLine(m);
}
}
}
Applying the Any condition on required in this way should give you the elements that match - I'm not sure if you should use StartsWith or Contains, that depends on your requirements.
If selected and required lists are large enough the following is faster than the accepted answer:
static void Main(string[] args)
{
List<string> selected = new List<string> { "A", "B", "B.1", "B.11", "C" };
List<string> required = new List<string> { "B", "C" };
required.Sort();
var matching = selected.Where(s =>
{
int index = required.BinarySearch(s);
if (index >= 0) return true; //exact match
index = ~index;
if (index == 0) return false;
return s.StartsWith(required[index - 1]);
});
foreach (string m in matching)
{
Console.WriteLine(m);
}
}
Given n = required.Count and m = required.Count the accepted answer algorithm complexity is O(n*m). However what I propose has a better algorithm complexity: O((n+m)*Log(n))
This query finds any match that exists in two lists. If a value exists in both lists, it returns true, otherwise false.
List<string> listString1 = new List<string>();
List<string> listString2 = new List<string>();
listString1.Add("A");
listString1.Add("B");
listString1.Add("C");
listString1.Add("D");
listString1.Add("E");
listString2.Add("C");
listString2.Add("X");
listString2.Add("Y");
listString2.Add("Z");
bool isItemExist = listString1.Any(x => listString2.Contains(x));
i have two lists having few elements in common, i want to remove duplicates events except few as described below..and the order of the string must be same and both list may not contain same no of elements?
list A: List B
ASCB ASCB
test1 test1
test2 test5
test3 test3
test4 test6
Arinc Arinc
testA testC
testB testB
testC
tesctD
now i want to remove all common elements in two list except elements ASCB, ARINC.. how to do that can any one help me in that...
I would just store the special values ( ASCB, ARINC, ect ) in their own list so I can use Except to get the difference between the two sets. You can add the special values in afterwards.
List<string> except = ListA.Except(ListB).Concat(listB.Except(ListA)).Concat(SpecialValues).ToList();
You have to call except twice because first we get items in A that are not in B. Then we add items that are in B but not in A. Finally we add the special values (I'm assuming SpecialValues is a collection with the strings you don't want removed).
You'd have to test performance as I suspect it's not the most efficient.
List<string> wordstoKeep = new List<string>() { "ASCB", "Arinc" };
foreach (string str in listB)
{
int index = listA.FindIndex(x => x.Equals(str, StringComparison.OrdinalIgnoreCase));
if (index >= 0)
{
if (!wordstoKeep.Any(x => x.Equals(str, StringComparison.OrdinalIgnoreCase)))
listA.RemoveAt(index);
}
else
listA.Add(str);
}
var listA = new List<string>{"ASCB","test1","test2"};
var listB = new List<string>{"ASCB","test1","test2"};
var combinedList = listA.Where(a => a.Contains("test"))
.Concat(listB.Where(b => b.Contains("test")))
.Distinct().Dump();
outputs 'test1', 'test2'
your filter conditions are contained in your Where clause.
Where can be whatever condition you want to filter by:
Where(a => a != "ASCB" or whatever...
Concat joins the two lists. Then call Distinct() to get unique entries.
Going off the requirement that order must be the same
if(B.Count != A.Count)
return;
List<String> reserved = new List<string>{ "ARCB", "ARINC" };
for (int i = A.Count -1; i >= 0; i--)
{
if (!reserved.Contains(A[i].ToUpper()) && A[i] == B[i])
{
A.RemoveAt(i);
B.RemoveAt(i);
}
}
This works:
var listA = new List<string>()
{
"ASCB",
"test1",
"test2",
"test3",
"test4",
"Arinc",
"testA",
"testB"
};
var listB = new List<string>()
{
"ASCB",
"test1",
"test5",
"test3",
"test6",
"Arinc",
"testC",
"testB"
};
var dontRemoveThese = new List<string>(){"ASCB", "Arinc"};
var listToRemove = new List<string>();
foreach (var str in listA)
if (listB.Contains(str))
listToRemove.Add(str);
foreach (var str in listToRemove){
if (dontRemoveThese.contains(str))
continue;
listA.Remove(str);
listB.Remove(str);
}
I like this solution because you can see what happens. I'd rather have 10 lines of code where it's obvious what happens than 1-3 lines of obscure magic.
I have a scenario as think
class a
{
String Username;
String val;
}
List<a> lst = new List<a>();
List<a> lstnew = new List<a>();
What i required is to that in lstnew i have some updated values in val Attribute (Only in Several Objects) , what i required is to update the lst with updated values in lstnew as the Username Attribute using LINQ
You can join the two lists on UserName, and then update the Values in the first list with those in the second.
For example, given this class and lists:
public class a
{
public string UserName { get; set; }
public string Value { get; set; }
}
List<a> list = new List<a>
{
new a { UserName = "Perry", Value = "A" },
new a { UserName = "Ferb", Value = "B" },
new a { UserName = "Phineas", Value = "C" }
};
List<a> newList = new List<a>
{
new a { UserName = "Phineas", Value = "X" },
new a { UserName = "Ferb", Value = "Y" },
new a { UserName = "Candace", Value = "Z" }
};
You can join to get the elements with common UserNames:
var common = from a1 in list
join a2 in newList on a1.UserName equals a2.UserName
select new { A1 = a1, A2 = a2 };
At this point, if I understand you correctly, you want to update the elements from the original list:
foreach(var c in common)
{
c.A1.Value = c.A2.Value;
}
at which point the elements in list look like:
UserName Value
-----------------
Perry A
Ferb Y
Phineas X
It sounds like you have two lists. One of which is named lst and contains a full list of usernames and a second one named lstnew that contains a list of usernames who have had their val property updated. I suggest unioning the untouched usernames with the ones that have been updated. This represents the most LINQ-friendly solution I can think of.
var updatedList = Enumerable.Union(
lst.Where(x => !lstnew.Any(y => y.Username == x.Username)),
lstnew).ToList();
you should be able to use the .Zip() method to execute this.
lst.Zip(lstNew, (orig, new) => {
orig.Username = new.Username;
return orig;
});
the idea that you are getting each pair together, then instead of returning a new one, changing the orig.Username value and return the orig.
This should also do the trick. Zip method, propsed by Alastair Pitts assumes that both collections have the same order of elements and each element from first list has correspondent element in second list. My approach is more generic, it simply looks for corresponding element by comparing Username property. Still it assumes that for each element in lstNew there is corresponding element in lst.
lstNew.ForEach(new => lst.First(orig => orig.Username == new.Username).val = new.val);
I know this is an old question but a more elegant solution that I have developed, which is a slight improvement over the one given by #JeffOgata would be:
var newList= lst.GroupJoin(lstnew ,
i => i.UserName ,
j => j.UserName ,
(i, j) => j.FirstOrDefault()?? i );
Where lst is the original list and lstnew is the new list.
This will just replace the entire object in the first list with the corresponding object in the second list (the join) if one exists.
It is a slight improvement over the answer given by #JeffOgata
The result is the same.
If you have complex objects then iterating through each object then going through all the properties was a problem, simply replacing the old object with the new one was quicker.
This hopefully will help someone.
I'm trying to grab a single item from each of the Lists here, and combine them to make a unique name. This is just for kicks. :)
Here are the lists:
List<string> FirstNames = new List<string>()
{
"Sergio",
"Daniel",
"Carolina",
"David",
"Reina",
"Saul",
"Bernard",
"Danny",
"Dimas",
"Yuri",
"Ivan",
"Laura"
};
List<string> LastNamesA = new List<string>()
{
"Tapia",
"Gutierrez",
"Rueda",
"Galviz",
"Yuli",
"Rivera",
"Mamami",
"Saucedo",
"Dominguez",
"Escobar",
"Martin",
"Crespo"
};
List<string> LastNamesB = new List<string>()
{
"Johnson",
"Williams",
"Jones",
"Brown",
"David",
"Miller",
"Wilson",
"Anderson",
"Thomas",
"Jackson",
"White",
"Robinson"
};
I know I get a single item via an index, and I also know that I can use the Random class to generate a random number from 0 to ListFoo.Count.
What I don't know is how to check if a random permutation has already been drawn from the collections.
I've thought about using the tuple class:
List<Tuple<int,int,int>> permutations = new List<Tuple<int,int,int>>();
But I'm having a brainfart here. ;) Any guidance? I'm not really looking for the entire code to this simple problem, just a suggestion or hint.
EDIT
Thanks to the suggestions given here, here what I've come up with. Any room for improvements?
static void Main(string[] args)
{
List<string> FirstNames = new List<string>()
{
"Sergio",
"Daniel",
"Carolina",
"David",
"Reina",
"Saul",
"Bernard",
"Danny",
"Dimas",
"Yuri",
"Ivan",
"Laura"
};
List<string> LastNamesA = new List<string>()
{
"Tapia",
"Gutierrez",
"Rueda",
"Galviz",
"Yuli",
"Rivera",
"Mamami",
"Saucedo",
"Dominguez",
"Escobar",
"Martin",
"Crespo"
};
List<string> LastNamesB = new List<string>()
{
"Johnson",
"Williams",
"Jones",
"Brown",
"David",
"Miller",
"Wilson",
"Anderson",
"Thomas",
"Jackson",
"White",
"Robinson"
};
var permutations = new List<Tuple<int, int, int>>();
List<string> generatedNames = new List<string>();
Random random = new Random();
int a, b, c;
//We want to generate 500 names.
while (permutations.Count < 500)
{
a = random.Next(0, FirstNames.Count);
b = random.Next(0, FirstNames.Count);
c = random.Next(0, FirstNames.Count);
Tuple<int, int, int> tuple = new Tuple<int, int, int>(a, b, c);
if (!permutations.Contains(tuple))
{
permutations.Add(tuple);
}
}
foreach (var tuple in permutations)
{
generatedNames.Add(string.Format("{0} {1} {2}", FirstNames[tuple.Item1],
LastNamesA[tuple.Item2],
LastNamesB[tuple.Item3])
);
}
foreach (var n in generatedNames)
{
Console.WriteLine(n);
}
Console.ReadKey();
}
You are on the right track!
Every time you generate a name, add it to your tuple list
//Create the tuple
Tuple <int, int, int> tuple = new Tuple<int, int, int>(index1, index2, index3)
if(!permutations.Contains(tuple))
{
permutations.Add(tuple);
//Do something else
}
I would think the simplest solution is to just the stuff the assembled name into a HashSet<string> which will ensure the list of created names is unique.
An alternative to the HashSet answer is to build all of the possible combinations in advance, shuffle them, then store them in a Queue, where you can retrieve them one at a time. This will avoid having to check the existing ones every time you build a new one, and will still be random.
This only works if you don't have a large set to begin with, since the work involved in creating the complete list and shuffling it would be huge for a large set of data.
It's really easy to generate them all using LINQ:
var combs =
(from first in FirstNames
from second in LastNamesA
from third in LastNamesB
select new Tuple<string, string, string>(first, second, third)).ToList();
After this, if you need to take unique elements from the list randomly, just shuffle the list and then pick them one-by-one in order.
You can use the Knuth-Fisher-Yates algorithm (that's an in-place shuffle):
Random rand = new Random();
for (int i = combs.Count - 1; i > 0; i--)
{
int n = rand.Next(i + 1);
var mem = combs[i];
combs[i] = combs[n];
combs[n] = mem;
}
I would create a HashSet<int> and store the numeric representation of the picks (eg 135 for first, third and 5th or use 010305) and then check if they are in the set.
Create a new tuple with 3 random digits
Check if permutations contains your new tuple
If not => Add new tuple to the list. If yes, start with point 1 again.