I cannot wrap my head around why this code generates a lot of null-lines:
int nr = 0;
foreach (var item in lists.Select(x => x.match_id))
{
foreach (var match in lists)
{
Console.Write(match.nickname
.Where(x => lists[nr].match_id == match.match_id)
.Select(z => match.nickname)
.FirstOrDefault());
}
nr++;
}
lists is an array of objects. The output:
Below all of the nulls are the next records, and then more nulls etc. Why?
To not output the null, you need to not call Console.Write if the value is null.
Try something like this:
int nr = 0;
foreach (var item in lists.Select(x => x.match_id))
{
foreach (var match in lists)
{
var n = match.nickname
.Where(x => lists[nr].match_id == match.match_id)
.Select(z => match.nickname)
.FirstOrDefault();
if (n != null)
{
Console.Write(n);
}
}
nr++;
}
You are looping twice through the same Array. I think you want to do:
for(int i = 0; i < lists.length; i++){
Console.Write(item.nickname
.Where(x=> lists[i].match_id === item.match_id)
.Select( z=> item.nickname)
.FirstOrDefault());
}
My 2 cents after a quick look..
Related
I have a method that returns a collection that has a duplicate value.
static List<string> GenerateItems()
{
var _items = new List<string>();
_items.Add("Tase");
_items.Add("Ray");
_items.Add("Jay");
_items.Add("Bay");
_items.Add("Tase");
_items.Add("Man");
_items.Add("Ran");
_items.Add("Ban");
return _items;
}
I want to search through that collection and find the first place that duplicate value is located and start collecting all the values from the first appearance of the duplicate value to its next appearance. I want to put this in a collection but I only want the duplicate value to appear once in that collection.
This is what I have so far but.
static void Main(string[] args)
{
string key = "Tase";
var collection = GenerateItems();
int index = collection.FindIndex(a => a == key);
var matchFound = false;
var itemsBetweenKey = new List<string>();
foreach (var item in collection)
{
if (item == key)
{
matchFound = !matchFound;
}
if (matchFound)
{
itemsBetweenKey.Add(item);
}
}
foreach (var item in itemsBetweenKey)
{
Console.WriteLine(item);
}
Console.ReadLine();
}
There must be an easier way of doing this. Perhaps with Indexing or a LINQ query?
You can do something like that
string key = "Tase";
var collection = GenerateItems();
int indexStart = collection.FindIndex(a => a == key);
int indexEnd = collection.FindIndex(indexStart+1, a => a == key);
var result = collection.GetRange(indexStart, indexEnd-indexStart);
You can use linq select and group by to find the first index and last index of all duplicates (Keep in mind if something is in the list more then 2 times it would ignore the middle occurences.
But I personally think the linq for this seems overcomplicated. I would stick with simple for loops and if statements (Just turn it into a method so it reads better)
Here is a solution with Linq to get all duplicate and all values between those duplicates including itself once as you mentioned.
var collection = GenerateItems();
var Duplicates = collection.Select((x,index) => new { index, value = x })
.GroupBy(x => x.value)//group by the strings
.Where(x => x.Count() > 1)//only take duplicates
.Select(x=>new {
Value = x.Key,
FirstIndex = x.Min(y=> y.index),//take first occurenc
LastIndex = x.Max(y => y.index)//take last occurence
}).ToList();
var resultlist = new List<List<string>>();
foreach (var duplicaterange in Duplicates)
resultlist .Add(collection.GetRange(duplicaterange.FirstIndex, duplicaterange.LastIndex - duplicaterange.FirstIndex));
Try this function
public List<string> PickOut(List<string> collection, string key)
{
var index = 0;
foreach (var item in collection)
{
if (item == key)
{
return collection.Skip(index).TakeWhile(x=> x != key).ToList();
}
index++;
};
return null;
}
First finding the duplicate key then find the second occurrence of the item and then take result.
var firstduplicate = collection.GroupBy(x => x)
.Where(g => g.Count() > 1)
.Select(g => g.Key).First();
var indices = collection.Select((b, i) => b == firstduplicate ? i : -1).Where(i => i != -1).Skip(1).FirstOrDefault();
if (indices>0)
{
var result = collection.Take(indices).ToList();
}
How to convert below c# nested for loop to linq...?
list = objBLForms.GetForms(Ids);
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j < list.Count; j++)
{
if (list[i].StateId == list[j].StateId &&
list[i].PayerId == list[j].PayerId && i != j)
{
if (string.IsNullOrEmpty(list[i].Tax))
{
list.Remove(list[i]);
}
else
{
list.Remove(list[j]);
}
}
}
}
I want to Remove duplicate payers with same state..And if any state tax is present, i wanted to remove the other duplicate one i,e; the duplicate one which is having no state tax...
I have achived it by using the nested for loop as shown above.
is there any way to do it in linq..I dont't know anything about linq.
Am very new to linq,Thanks in advance
The logic of your code is actually removing EVERYTHING that has string.IsNullOrEmpty(Tax), and only keeping first record that has value in Tax. Then, how about this
list
.Where(l => !string.IsNullOrEmpty(l.Tax))
.GroupBy(l => new {l.StateId, l.PayerId})
.Select(group => group.First())
.ToArray();
This seems about right to me:
list =
list
.OrderByDescending(x => x.Tax)
.GroupBy(x => new { x.StateId, x.PayerId })
.SelectMany(x => x.Take(1))
.ToList();
Please have a look in the below code, I need an output in OrderedListDesc = {7,6,5,4,1,2,3,8,9} instead of {4,5,6,7,1,2,3,8,9}.
List<long> List = new List<long>() { 1,2,4,5,3,8,6,7,9 };
List<long> ListAsc = new List<long>() { 4,5,6,7 };
List<long> ListDesc = new List<long>() { 7,6,5,4 };
var OrderedListAsc = List.OrderBy(b => ListAsc.FindIndex(a => a == b)).ToList();
foreach (var l in OrderedListAsc)
{
Console.Write(l+" ,");
}
Console.WriteLine();
var OrderedListDesc = List.OrderByDescending(b => ListDesc.FindIndex(a => a == b)).ToList();
foreach (var l in OrderedListDesc)
{
Console.Write(l + " ,");
}
It is really simple if you think about it:
The order of the elements found in ListDesc should be the number itself, then you got your result:
var OrderedListDesc = List.OrderByDescending(b => ListDesc.Any(a => a == b) ? b : 0).ToList();
foreach (var l in OrderedListDesc)
{
Console.Write(l + " ,");
}
If you want to see what's happening, that is, why you're getting things in the wrong order, run this:
foreach (var i in List)
{
Console.WriteLine("{0}, {1}", i, ListDesc.FindIndex(a => a == i));
}
There's no need for ListDesc anyway. Just use ListAsc:
var OrderedListDesc = List.OrderByDescending(b => ListAsc.FindIndex(a => a == b)).ToList();
Or, use ListDesc and call OrderBy rather than OrderByDescending:
var OrderedListDesc = List.OrderBy(b => ListDesc.FindIndex(a => a == b)).ToList();
If you notice the problem is, when an element(value) not found FindIndex returns -1, which will appear first in order. Assign the maximum value when element is not found.
var OrderedListDesc = List.OrderBy(b =>
{
var index = ListDesc.FindIndex(a => a == b);
return index==-1? int.MaxValue : index;
}).ToList();
A small tip (not relating to issue), if you want to print , separated values you could simply use string.Join as below.
Console.WriteLine(string.Join(",", OrderedListDesc));
Output:
7 ,6 ,5 ,4 ,1 ,2 ,3 ,8 ,9 ,
Check this Fiddle
Getting error Collection was modified; enumeration operation may not execute.
var toUpdateItm = MC_CRM_T001A.ItemDetails
.Where(X => X.CatNo == SelectedCRM_T001A.CatNo);
foreach (var itm in toUpdateItm)
{
int x = MC_CRM_T001A.PartDetails.IndexOf(MC_CRM_T001A.PartDetails
.Where(X => X.cat_item_id == itm.id)
.FirstOrDefault()
);
if (x >= 0 && x!=null)
{
MC_CRM_T001A.PartDetails.RemoveAt(x);
}
}
foreach (var itm in toUpdateItm)
{
if (itm.CatNo == SelectedCRM_T001A.CatNo)
{
MC_CRM_T001A.ItemDetails.Remove(itm);
}
}
You can't modify the list you're looping over. Change for foreach calls to foreach (var itm in toUpdateItem.ToList()), which will create a copy of the list, instead.
Also, you can express this code more cleanly without all the IndexOf stuff:
var toUpdateItm = MC_CRM_T001A.ItemDetails.Where(X => X.CatNo == SelectedCRM_T001A.CatNo).ToList();
foreach (var itm in toUpdateItm.ToList())
{
var item = MC_CRM_T001A.PartDetails.FirstOrDefault(X => X.cat_item_id == itm.id);
if (item != null) { MC_CRM_T001A.PartDetails.Remove(item); }
if (itm.CatNo == SelectedCRM_T001A.CatNo) { MC_CRM_T001A.ItemDetails.Remove(itm);
}
You don't need two loops either.
I have an IEnumerable<IEnumerable<T>> collection that I want to convert to a single dimension collection. Is it possible to achieve this with a generic extension method? Right now I'm doing this to achieve it.
List<string> filteredCombinations = new List<string>();
//For each collection in the combinated results collection
foreach (var combinatedValues in combinatedResults)
{
List<string> subCombinations = new List<string>();
//For each value in the combination collection
foreach (var value in combinatedValues)
{
if (value > 0)
{
subCombinations.Add(value.ToString());
}
}
if (subCombinations.Count > 0)
{
filteredCombinations.Add(String.Join(",",subCombinations.ToArray()));
}
}
If it's not possible to get a generic solution, how can I optimize this in an elegant fashioned way.
You can use the Enumerable.SelectMany extension method for this.
If I read your code correctly, the code for that would be:
var filteredCombinations = combinatedResults.SelectMany(o => o)
.Where(value => value > 0)
.Select(v => v.ToString());
Edit: As commented, the above code is not joining each element of the subsets to a string, as the original code does. Using the built-in methods, you can do that using:
var filteredCombinations = combinatedResults
.Where(resultSet => resultSet.Any(value => value > 0)
.Select(resultSet => String.Join(",",
resultSet.Where(value => value > 0)
.Select(v => v.ToString()).ToArray()));
Here you go:
var strings = combinedResults.Select
(
c => c.Where(i => i > 0)
.Select(i => i.ToString())
).Where(s => s.Any())
.Select(s => String.Join(",", s.ToArray());
I would personally use Enumerable.SelectMany, as suggested by driis.
However, if you wanted to implement this yourself, it would be much cleaner to do:
IEnumerable<T> MakeSingleEnumerable<T>(IEnumerable<IEnumerable<T>> combinatedResults)
{
foreach (var combinatedValues in combinatedResults) {
foreach (var value in combinatedValues)
yield return value;
}
}
You asked two different questions. The one you described in the title is already answered by drilis.
But your example code is a different problem. We can refactor it in stages. Step 1, build the subCombinations list using some Linq:
List<string> filteredCombinations = new List<string>();
//For each collection in the combinated results collection
foreach (var combinatedValues in combinatedResults)
{
var subCombinations = combinatedValues.Where(v => v > 0)
.Select(v => v.ToString())
.ToList();
if (subCombinations.Count > 0)
filteredCombinations.Add(string.Join(",",subCombinations.ToArray()));
}
Now the outer loop, leaving us with just this:
var filteredCombinations = combinatedResults
.Select(values => values.Where(v => v > 0)
.Select(v => v.ToString())
.ToArray())
.Where(a => a.Count > 0)
.Select(a => string.Join(",", a));
use linq SelectMany