Concatenating strings in two lists to create a third list - c#

I have two lists of items, can you please guide me how I can concatenate values of both and add concatenated value into third list as a value.
For example if List<string> From has A,B,C and List<string> To has 1,2,3 then List<string> All should have A1,B2,C3. I'd preferably like to use a lambda expression.

Use Linq's Zip extension method:
using System.Linq;
...
var list1 = new List<string> { "A", "B", "C" };
var list2 = new List<string> { "1", "2", "3" };
var list3 = list1.Zip(list2, (x, y) => x + y).ToList(); // { "A1", "B2", "C3" }

That's not concatenation - that's matching two sequences pairwise. You do it with LINQ's Zip method:
Zip applies a specified function to the corresponding elements of two sequences, producing a sequence of the results.
var res = from.Zip(to, (a,b) => a + b).ToList();

If item's count are equal in both lists then you can do:
var list3 = list1.Select((item, index) => item + list2[index]).ToList();

Related

join 2 lists and create one to many relationship [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 11 months ago.
Improve this question
Is it possible to join 2 lists and create one to many relationship?
For example,
list 1:
{"High", "Med", "Low"}
list 2:
{"Submitted", "In Progress", "Draft", "Rejected"}
final list, I will have values like this:
{
{"High", "Submitted"}, {"High", "In Progress"},{"High", "Draft"}, {"High", "Rejected"},
{"Med", "Submitted"}, {"Med", "In Progress"},{"Med", "Draft"}, {"Med", "Rejected"},
{"Low", "Submitted"}, {"Low", "In Progress"},{"Low", "Draft"}, {"Low", "Rejected"}
}
Not sure if this is what you are looking for, but you can use Select and SelectMany to create the final List of KeyVaulePair.
var list1 = new List<string>() { "High", "Medium", "Low" };
var list2 = new List<string>() { "Submitted", "In-Progress", "Draft", "Rejected" };
var joined = list1.SelectMany(val1 => list2.Select(val2 => new KeyValuePair<string, string>(val1, val2)));
foreach(var res in joined)
{
Console.WriteLine(res.Key + "," + res.Value);
}
If you want to use imperative style of coding, then just create 2 for loops
It seems, that you are looking for a Cartesian Join, you can do it with a help of Linq:
var list1 = new List<string>() {
"High", "Medium", "Low" };
var list2 = new List<string>() {
"Submitted", "In-Progress", "Draft", "Rejected" };
// I've combined values as named tuple: (string first, string second)
// but you can use anonymous class, or just concat string strings
var joined = list1
.SelectMany(item1 => list2.Select(item2 => (first: item1, second: item2)));
.ToList();
Let's have a look:
Console.Write(string.Join(Environment.NewLine, joined));
Outcome:
(High, Submitted)
(High, In-Progress)
(High, Draft)
(High, Rejected)
(Medium, Submitted)
(Medium, In-Progress)
(Medium, Draft)
(Medium, Rejected)
(Low, Submitted)
(Low, In-Progress)
(Low, Draft)
(Low, Rejected)
LINQ method syntax for joins is pretty ugly and even counterintuitive, IMHO; query syntax looks much nicer/easier to read:
from s in list1
from t in list2
select new { s, t }
Or as a tuple:
from s in list1
from t in list2
select ( s, t )
If you want to do Cartesian product and want to store it in text-value pair then you can use List with SelectListItem. It will give you list with text-value pair.
var list1 = new List<string>() { "High", "Medium", "Low" };
var list2 = new List<string>() { "Submitted", "In-Progress", "Draft", "Rejected" };
List<SelectListItem> list3 = new List<SelectListItem>();
foreach (string str in list1)
{
foreach(string str2 in list2)
{
list3.Add(new SelectListItem()
{ Text = str, Value = str2 });
}
}
You can use the join method from LINQ:
List<(string,string)> joined = list1.Join(list2, x => true, y => true, (x,y) => (x,y)).ToList();
The second and third parameter are selectors for list1 and list2. If both are the same, a joined value will be created. If we give the same constant value for both selectors, the joining condition is always fulfilled and hence all possible pairs are created.
Online demo: https://dotnetfiddle.net/JaK6ff

C#: How do i get 2 lists into one 2-tuple list in

I have 2 Lists. First one is Type string. The second is type object. Now I want to get both lists into a Tuple<string,object>.
like this
var List = new(string list1, object list2)[]
How do I do this?
I had to create 2 seperate lists, because I am Serializing the object and the serializing wouldn't work if i had a List<Tuple<string,object>> in the first place.
Both lists can get big so maybe with foreach loop?
You can use the Zip method to create one list of the two:
var lst = new List<string>() { "a", "b" };
var obj = new List<object>() { 1, 2 };
var result = lst.Zip(obj, (x, y) => new Tuple<string, object>(x, y))
.ToList();
You can use the Linq Zip method:
List<string> list1 = GetStrings();
List<object> list2 = GetObjects();
var merged = list1.Zip(list2, (a, b) => Tuple.Create(a, b));

Contains without order

I want to search a list of strings using a set of characters and want to find matches regardless of order. For example if my list contains
List<string> testList = new List<string>() { "can", "rock", "bird" };
I want to be able to search using "irb" and have it return bird. I have to do this many times so I am looking for the most efficient way of doing it.
var query = "irb";
List<string> testList = new List<string>() { "can", "rock", "bird" };
var result = testList.Where(i => query.All(q => i.Contains(q)));
For each item in the testList test to see if it contains all the letters in query
For your scenario, you need to check each character of word in another list of word.
For that, you can do like this :
// Checks whether all character in word is present in another word
Func<string, string, bool> isContain = (s1, s2) =>
{
int matchingLength = 0;
foreach (var c2 in s2.ToCharArray())
{
foreach (var c1 in s1.ToCharArray())
{
if (c1 == c2)
++matchingLength;
}
}
// if matched length is equal to word length given, it would be assumed as matched
return s2.Length == matchingLength;
};
List<string> testList = new List<string>() { "can", "rock", "bird" };
string name = "irb";
var fileredList = testList.Where(x => isContain(x, name));
If you don't care about matching duplicates than checking if all characters in a sequence you are searching for are contained in the word would do for predicate:
"irb".Except("bird").Count() == 0
And whole condition:
List<string> testList = new List<string>() { "can", "rock", "bird" };
var search = "irb";
var matches = testList.Where(word => !search.Except(word).Any());
Notes:
you need to normalize all words to lowercase if you need mixed case letters to match.
if performance of searching for different values is critical - convert search string to HashSet first and do except manually.
if you need to match different values against same list many times - convert list of strings to list of HashSet and use search.All(c => wordAsHashSet.Contains(c)) as condition.
You can use linq to achieve this
List<string> testList = new List<string>() { "can", "rock", "bird" };
var lst = testList.Where(x => x.ToUpperInvariant().Contains("IRD")).ToList();
Make sure you also compare the cases using ToUpper and the string you want to compare also make it UpperCase

Compare value to array of strings using StartsWith

I have an array:
string[] exceptions = new string[] { "one", two", "one_1", "three" };
.. I want to be able to say:
var result = from c in myCollection
where not c.Property[3].Value.StartWith(exceptions)
select c;
So I want myCollection to be filtered to only show those records whose Property[3].Value does not StartWith a value in the exceptions array. I know StartsWith doesn't take a collection so I'm unsure if this is possible via LINQ or not.
Is this possible in LINQ?! Or am I trying to shoehorn my problem into a LINQ solution?
EDIT: I should say, Contains is not an option since I only want to exclude elements whose property startswith the exception string.
var result = myCollection.Where(c =>
exceptions.All(e =>
!c.Property[3].Value.StartsWith(e));
Try this:
string[] exceptions = new string[] { "one", "two", "one_1", "three" };
var result = from c in myCollection
where !exceptions.Any(exception =>
c.Property[3].Value.StartsWith(exception))
select c;
You could use IndexOfAny (and check result is index position zero) as that takes a collection.
You can select the collection of item you don't want then do a IEnumerable.Except().
I should look like this :
var result = from c in myCollection
where not c.Property[3].Value.StartWith(exceptions)
select c;
var finalResult = myCollection.Except(myCollection.Select(i => i.StartWith(exception)));
var result = myCollection
.where(
rs=>exceptions
.where(
rs1=>!rs.property[3].value.startsWith(rs1)
)
)

Find duplicates in a collection of lists

If I have a dictionary containing 2 or more lists, how can I quickly find shared items between these lists and add these shared items to a list external to the dictionary?
For example:
list1:
eng;English
lir;Liberian English
list2:
eng;English
bav;Vengo
list3:
lat;Latin
extList:
eng;English
This shared item is then removed from the lists inside the dictionary.
I have added list3 to show that a superfluous item may be ignored, and that I have specified 2 or more lists.
As I understand you have two lists and need to find intersection between those lists and add this intersection to the third list:
var list1 = new[] { "eng;English", "lir;Liberian", "English" };
var list2 = new[] { "eng;English", "bav;Vengo", "English" };
extList.AddRange(list1.Intersect(list2));
Suppose we have a list of lists (or a dictionary, which would add a Key):
List<List<string>> lists = new List<List<string>>()
{
new List<string> {"Hello", "World", "7"},
new List<string> {"Hello", "7", "Person"},
new List<string> {"7", "7", "Hello"}
};
You can find items that are present in all lists:
List<string> extList = lists.Cast<IEnumerable<string>>()
.Aggregate((a, b) => a.Intersect(b)).ToList();
If you want to get strings that are common to just a few lists, you can use:
var counts = from str in lists.SelectMany(list => list)
group str by str into g
where g.Count() > 1
select new { Value = g.Key, Count = g.Count() };
You can drop the last line if you don't care how many times each word appears. Note that this will not tell you in which list the word is.
Here's a function that will take a dictionary, remove any string that is in more than one list in the dictionary, and return the list of strings it removed:
static List<string> FindAndRemoveDuplicates(Dictionary<string, List<string>> data)
{
// find duplicates
var dupes = new HashSet<string>(
from list1 in data.Values
from list2 in data.Values
where list1 != list2
from item in list1.Intersect(list2)
select item);
// remove dupes from lists in the dictionary
foreach (var list in data.Values)
list.RemoveAll(str => dupes.Contains(str));
// return a list of the duplicates
return dupes.ToList();
}

Categories