Related
So I have a list of items -> A, B, C, D.
C and D are included more than once, and A and B, more than twice. This list can go on and on, so we do not know how many times an item will be included.
I need to create a new list that will have the item in one column and the number of instances of that item in another column, but I do not know how to do this. I may need to use a tuple or a class, but I am not fully sure how to implement either...
What you actually need is to Group the items of your list and perform a group operation, which is Count in your case to calculate how many times does it exist.
This is how you may initialize your list:
List<string> myList = new List<string>() { "A", "B", "C", "D", "A", "B", "C", "D", "A", "B" };
and then you will group it using GroupBy function and apply the Count aggregate function on each group.
myList
.GroupBy(item => item)
.Select(g => new {Key = g.Key, Count = g.Count()})
.ToList();
This will result in the table you need.
You can try like this:
var myList = new List<String>() { "A","B", "C", "D","A","B", "C", "D", "A","B"};
var grp = myList.GroupBy( x => x );
foreach( var g in grp )
{
Console.WriteLine( "{0} {1}", g.Key, g.Count() );
}
DOTNET FIDDLE
char[] items = new[] { 'A', 'B', 'C', 'D', 'A', 'B', 'C', 'D', 'A', 'B' };
Dictionary<char, int> counts = new();
foreach(char c in items)
{
if (counts.TryGetValue(c, out int n))
{
counts[c] = n + 1;
}
else
{
counts.Add(c, 1);
}
}
While not a one liner, a simple and fast option.
I may need to use a tuple or a class, but I am not fully sure how to implement either...
Since you mentioned you may want to use a class, here is an example:
public class TextCount
{
public string Text { get; set; }
public int Count { get; set; }
}
public class Program
{
public static void Main()
{
// Initialize the list of strings
List<string> data = new List<string> { "A", "B", "C", "D", "A", "B", "C", "D", "A", "B" };
// Use LINQ to group the strings by their value and count the number of occurrences of each string
List<TextCount> result = data
.GroupBy(s => s)
.Select(g => new TextCount { Text = g.Key, Count = g.Count() })
.ToList();
// Print the results
foreach (TextCount sc in result)
{
Console.WriteLine("{0}: {1}", sc.Text, sc.Count);
}
}
}
Demo: https://dotnetfiddle.net/2FRBbK
I want to convert two lists with the same index into a single list.
Given this:
List<double> ListA = new List<double> { 1, 2, 3, 4, 5 };
List<string> ListB = new List<string> { "A","B","C","D","E" };
until now, I used this:
List<string> UNHAPPY = new List<string>();
for (int ListIndex = 0; ListIndex < ListA.Count; ListIndex++)
{
UNHAPPY.Add(ListB[ListIndex]+ListA[ListIndex].ToString());
}
// such that UNHAPPY == new List<string> {"A1", "B2", "C3", "D4", "E5"}
But I really want to use short code as possible, like this (Similar to Enumerable.ConvertAll):
List<string> HAPPY = SOME_CONTAINER(ListA, ListB).SOME_SELECTOR((a,b) => b + a.ToString());
// such that HAPPY == new List<string> {"A1", "B2", "C3", "D4", "E5"}
Is there any quick method for this? Thank you so mush in advance!
LINQ has a method for this, it's called Zip:
var res = ListA.Zip(ListB, (a,b) => $"{b}{a}");
It takes two sequences and a Func delegate, and applies the delegate to pairs of items coming from the two sequences.
Note: call of ToString on a is redundant, C# will concatenate a string to anything, including an int, by calling ToString on the corresponding object. I prefer string interpolation, especially when you need to concatenate more than two items.
You are looking for Enumerable.Zip
first.Zip(second, (f, s) => f + s.ToString());
You can do this with a Zip:
ListA.Zip(ListB, (a,b) => b + a.ToString());
This produces:
csharp> List<double> ListA = new List<double> { 1, 2, 3, 4, 5 };
csharp> List<string> ListB = new List<string> { "A","B","C","D","E" };
csharp> ListA.Zip(ListB, (a,b) => b + a.ToString());
{ "A1", "B2", "C3", "D4", "E5" }
Zip itererates over the two iterables concurrently and produces the product constructed by the function. From the moment one of the iterables is exhausted, the Zip stops.
This i probably a simple question, but I'm still new to C# and LINQ (which I assume is useful in this case).
I have a List with different groups:
e.g. List<string>() { a, a, b, c, a, b, b };
I would like to make a corresponding List (sort of GroupID), holding:
List<int>() { 1, 1, 2, 3, 1, 2, 2}
The amount of different groups could be anything from 1-x, so a dynamic generation of the List is needed. Duplicate groups should get same numbers.
All this should end up in a LINQ zip() of the two into 'CombinedList', and a SqlBulkCopy with other data to a database with a foreach.
table.Rows.Add(data1, data2, data3, CombinedList.GroupID.toString() ,CombinedList.Group.ToString());
Hope it makes sense.
Example:
List<string>() { a, a, b, c, a, b, b };
This list holds 3 unique groups: a, b and c.
assign an incrementing number to the groups, starting from 1:
a = 1, b = 2, c = 3.
The generated result list should then hold
List<string>() { 1, 1, 2, 3, 1, 2, 2 };
This works for me:
var source = new List<string>() { "a", "a", "b", "c", "a", "b", "b" };
var map =
source
.Distinct()
.Select((x, n) => new { x, n })
.ToDictionary(xn => xn.x, xn => xn.n + 1);
var result =
source
.Select(x => new { GroupIP = map[x], Value = x });
I get this result:
Generate a List:
var strings = new List<string>() { "a", "a", "b", "c", "a", "b", "b" };
var uniqueStrings = strings.Distinct().ToList();
var numbers = strings.Select(s => uniqueStrings.IndexOf(s)).ToList();
This produces:
List<int> { 0, 0, 1, 2, 0, 1, 1 }
If you want to have your values starting at 1 instead of 0, then modify the last line to include +1 as per below:
var numbers = strings.Select(s => uniqueStrings.IndexOf(s) + 1).ToList();
Not sure but I think this can help you.
var keyValue = new List<KeyValuePair<int, string>>();
var listString = new List<string>() { "a", "a", "b", "c", "a", "b", "b"};
var listInt = new List<int>();
int count = 1;
foreach (var item in listString)
{
if(keyValue.Count(c=>c.Value == item) == 0)
{
keyValue.Add(new KeyValuePair<int, string>(count, item));
count++;
}
}
foreach (var item in listString)
{
listInt.Add(keyValue.Single(s=>s.Value == item).Key);
}
How about this:
int groupId = 1;
var list = new List<string>() { "a", "a", "b", "c", "a", "b", "b" };
var dict = list
.GroupBy(x => x)
.Select(x => new {Id = groupId++, Val = x})
.ToDictionary(x => x.Val.First(), x => x.Id);
var result = list.Select(x => dict[x]).ToList();
Suppose I have two Lists<myObject> where myObject consists of the two properties
Id (of type Int) and
Value (of type Double)
I need to get a list out of these two lists that is made of (anonymous) objects like this:
Id, [Double value from List 1], [Double value from List 2]
So if for a given Id both lists contain a value, it should look like this example:
12, 21.75, 19.87
If one list does not contain an object with an Id that is present in the other list, the value should be null:
15, null, 22.52
How can I achieve that?
Update: I know how I could get such a list, of course, but I'm looking for the most performant way to do it, preferrably by using some witty Linq magic.
Not sure how optimized this is, but should suit your needs - Assuming I understood what you wanted:
var enumerable1 = new[]
{
new {Id = "A", Value = 1.0},
new {Id = "B", Value = 2.0},
new {Id = "C", Value = 3.0},
new {Id = "D", Value = 4.0},
new {Id = "E", Value = 5.0},
};
var enumerable2 = new[]
{
new {Id = "A", Value = 6.0},
new {Id = "NOT PRESENT", Value = 542.23},
new {Id = "C", Value = 7.0},
new {Id = "D", Value = 8.0},
new {Id = "E", Value = 9.0},
};
var result = enumerable1.Join(enumerable2, arg => arg.Id, arg => arg.Id,
(first, second) => new {Id = first.Id, Value1 = first.Value, Value2 = second.Value});
foreach (var item in result)
Console.WriteLine("{0}: {1} - {2}", item.Id, item.Value1, item.Value2);
Console.ReadLine();
The resulting output would be something akin to:
A: 1 - 6
C: 3 - 7
D: 4 - 8
E: 5 - 9
Don't really see why you would want null values returned, unless you absolutely need to (Besides, double is not-nullable, so it would have to be the resulting combined entry that would be null instead).
The requirement is slightly unclear. Do you want a Cartesian product or a join on Id? If the latter, then this should work:
var result = from l1 in list1
join l2 in list2
on l1.Id equals l2.Id
select new {l1.Id, Value1 = l1.Value, Value2 = l2.Value};
If you actually want a full outer join, see this.
**Let say tempAllocationR is list 1 and tempAllocationV is List2 **
var tempAllocation = new List<Object>();
if (tempAllocationR.Count > 0 && tempAllocationV.Count > 0)
{
foreach (TempAllocation tv in tempAllocationV)
{
var rec = tempAllocationR.FirstOrDefault(tr => tr.TERR_ID == tv.TERR_ID && tr.TERR == tv.TERR && tr.Team == tv.Team);
if (rec != null)
{
rec.Vyzulta = tv.Vyzulta;
}
else
{
tempAllocationR.Add(tv);
}
}
tempAllocation = tempAllocationR;
}}
I have several arrays, like:
var arr1 = new[] { "A", "B", "C", "D" };
var arr2 = new[] { "A", "D" };
var arr3 = new[] { "A", "B", };
var arr4 = new[] { "C", "D" };
var arr5 = new[] { "B", "C", "D" };
var arr6 = new[] { "B", "A", };
... etc.
How can I get most common combination of elements in all of those arrays?
In this case it is A and B, because they occur in arr1, arr3 and arr6, and C and D, because they occur in arrays arr1, arr4 and arr5.
Just to mention that elements can be in any kind of collection, ie. in ArrayLists also.
UPDATE uuhhh, I was not clear enough...... Most common combinations of two elements in an array. That's what I tried to show in example, but did not mention in my question.
Sorry
:-((
If you are sure that each item appears only once in each array, you could just concatenate them together and get the counts, for example:
var arrs = new[] { arr1, arr2, arr3, arr4, arr5, arr6 };
var intermediate = arrs.SelectMany(a => a)
.GroupBy(x => x)
.Select(g => new { g.Key, Count = g.Count() })
.OrderByDescending(x => x.Count);
var maxCount = intermediate.First().Count;
var results = intermediate.TakeWhile(x => x.Count == maxCount);
Or if you prefer query syntax, that would be:
var arrs = new[] { arr1, arr2, arr3, arr4, arr5, arr6 };
var intermediate =
from a in arrs.SelectMany(a => a)
group a by a into g
orderby g.Count() descending
select new { g.Key, Count = g.Count() };
var maxCount = intermediate.First().Count;
var results = intermediate.TakeWhile(x => x.Count == maxCount);
The result set will contain 3 items:
Key, Count
"A", 4
"B", 4
"D", 4
Update
Given your updated question, something like this should work:
var items = arrs.SelectMany(a => a).Distinct();
var pairs =
from a in items
from b in items
where a.CompareTo(b) < 0
select new { a, b };
var results =
(from arr in arrs
from p in pairs
where arr.Contains(p.a) && arr.Contains(p.b)
group arr by p into g
orderby g.Count() descending
select g.Key)
.First();
The logic here is:
First find all distinct items in any array
Then find every pair of items to search for
Get of every pair, grouped by a list of what arrays contain that pair
Order by the groups by the number of arrays that contain each pair, descending
Return the first pair
use a Dictionary which will store an element as an index, and the occurrence count as a value. Iterate each list and count the occurrences.
var arr1 = new[] { "A", "B", "C", "D" };
var arr2 = new[] { "A", "D" };
var arr3 = new[] { "A", "B", };
var arr4 = new[] { "C", "D" };
var arr5 = new[] { "B", "C", "D" };
var arr6 = new[] { "B", "A", };
var results = new List<IEnumerable<string>>() { arr1, arr2, arr3, arr4, arr5, arr6 }
.Select(arr => arr.Distinct())
.SelectMany(s => s)
.GroupBy(s => s)
.Select(grp => new { Text = grp.Key, Count = grp.Count() })
.OrderByDescending(t => t.Count)
.ToList();
Gives you {A, 4}, {B, 4}, {D, 4}, {C, 3}
var result = new IEnumerable<String>[] {arr1, arr2, arr3, arr4, arr5, arr6}
.SelectMany(a => a)
.GroupBy(s => s)
.GroupBy(g => g.Count())
.OrderByDescending(g => g.Key)
.FirstOrDefault()
.SelectMany(g => g.Key);
Your question is unclear as you have not clearly defined what you are looking for. In general, you could combine all the arrays into one large array and count the distinct elements. By then ordering the elements you can do whatever you intend to do with the "most common".
static void Main()
{
var arr1 = new[] { "A", "B", "C", "D" };
var arr2 = new[] { "A", "D" };
var arr3 = new[] { "A", "B", };
var arr4 = new[] { "C", "D" };
var arr5 = new[] { "B", "C", "D" };
var arr6 = new[] { "B", "A", };
List<string> combined = Combine(arr1, arr2, arr3, arr4, arr5, arr6);
var ordered = combined.OrderBy(i => i);//sorted list will probably help other functions work more quickly such as distinct
var distinct = ordered.Distinct();
var counts = new Dictionary<string, int>();
foreach (var element in distinct)
{
var count = ordered.Count(i => i == element);
counts.Add(element, count);
}
var orderedCount = counts.OrderByDescending(c => c.Value);
foreach (var count in orderedCount)
{
Console.WriteLine("{0} : {1}", count.Key, count.Value);
}
Console.ReadLine();
}
private static List<string> Combine(string[] arr1, string[] arr2, string[] arr3, string[] arr4, string[] arr5, string[] arr6)
{
List<string> combined = new List<string>();
combined.AddRange(arr1);
combined.AddRange(arr2);
combined.AddRange(arr3);
combined.AddRange(arr4);
combined.AddRange(arr5);
combined.AddRange(arr6);
return combined;
}
Outputs: A : 4, B : 4, D : 4, C : 3