Items is public list of MenuListItemViewModel items, in example below im creating new list with 2 elements:
Items = new List<MenuListItemViewModel>
{
new MenuListItemViewModel
{
Value = "500",
Letter = "D"
},
new MenuListItemViewModel
{
Value = "-500",
Letter = "W"
},
};
How to do exactly the same but with variable numbers of items i want to have in the list? Something like loop x times (like below, but it wont work in current state)
for (int i = 0; i < 5; i++)
{
new MenuListItemViewModel
{
Value = "500",
Letter = "D"
},
}
You can use LINQ:
Items = Enumerable.Range(0, number)
.Select(i => new MenuListItemViewModel
{
Value = "500",
Letter = "D"
}).ToList();
You can do
Items = new List<MenuListItemViewModel>();
for (int i = 0; i < 5; i++)
{
Items.Add(
new MenuListItemViewModel
{
Value = "500",
Letter = "D"
});
}
Related
I'm facing an issue while displaying multiple lists the value in a single row column.
Here is an example of code.
public class Program
{
static void Main(string[] args)
{
Dictionary<string, List<object>> keyvalues = new Dictionary<string, List<object>>();
keyvalues.Add("Code", new List<object>() { 1, 2, 3, 4 });
keyvalues.Add("Name", new List<object>() { "A", "B", "C", "D" });
keyvalues.Add("Age", new List<object>() { 20, 30, 40, 50 });
var listData = keyvalues.Select(x => x.Value).Select((x, i) => new { obj = x, index = i });
var listData = keyvalues.Select((x, iparent) => x.Value.Select((z, i) => new { value = string.Concat(z, x.Value[i]) }).ToList()).ToList();
Console.ReadLine();
}
}
Expected output
1A20
2B30
3C40
4D50
If you are using .Net 6, you could make use of the new 3 way Zip extension.
var result = keyvalues["Code"].Zip(keyvalues["Name"], keyvalues["Age"])
.Select(x=> $"{x.First}{x.Second}{x.Third}");
Why make it so complicated?
for(int x = 0; x<keyValues["Code"].Count; x++)
Console.WriteLine(
keyValues["Code"][x]+
keyValues["Name"][x]+
keyValues["Age"][x]
);
LINQ's a hammer; not every problem is a nail.
ps if you have N keys, you can easily turn it into a
var keys = new[]{"Code","Name","Age","Foo","Bar"};
for(...)
foreach(var k in keys)
... //some concat here or use the values directly eg adding to your page
You could easily use Zip here. However, you could roll your own
public static IEnumerable<string> DoStuff<T, T2>(Dictionary<T, List<T2>> source)
{
var max = source.Values.Max(x => x?.Count ?? 0);
for (var i = 0; i < max; i++)
yield return string.Concat(source.Values.Select(x => x.ElementAtOrDefault(i)));
}
Usage
var results = DoStuff(keyvalues);
Console.WriteLine(string.Join(Environment.NewLine,results));
Output
1A20
2B30
3C40
4D50
or
public static IEnumerable<string> DoStuff<T>(List<T>[] source)
{
var max = source.Max(x => x?.Count ?? 0);
for (var i = 0; i < max; i++)
yield return string.Concat(source.Select(x => x.ElementAtOrDefault(i)));
}
...
var results = DoStuff(keyvalues.Values.ToArray());
Console.WriteLine(string.Join(Environment.NewLine,results));
I have a problem with a list that I want to alter, before outputting it back to the client.
For the sake of the question I will post an example of the list and how I need to result to look, because I have looked at Intersect, Except and everything else I could think of, but didn't get the result I am looking for.
Example List:
1, 4, 6, 8
1, 2, 6, 8
2, 4, 6, 8
3, 4, 5, 7
Required Result:
1, 4, 6, 8 //Initial row
-, 2, -, - //Items that have not changed will show as a -
2, 4, -, -
3, -, 5, 7
I really hope I explained it well.
I would be happy to explain this further if needed.
Thanks in advance for the advice, so far I have wrecked my brain over this. ;)
What I tried is too much to type here, so here is what I have so far. Except simply won't do anything with the data because it thinks the rows are different, so they just stay the same.
private List<List<string>> FilterData(List<string[]> datatable)
{
List<string> previousRow = new List<string>();
List<string> currentRow = new List<string>();
List<string> rowDifferences = new List<string>();
List<List<string>> resultingDataset = new List<List<string>>();
foreach (var item in datatable)
{
if (previousRow == null)
{
previousRow = item.ToList();
continue;
}
currentRow = item.ToList();
rowDifferences = currentRow.Except(previousRow).ToList();
resultingDataset.Add(rowDifferences);
}
return resultingDataset;
}
Few things you have to change in your code;
Here is code:
private List<string[]> FilterData(List<string[]> datatable)
{
// List is made of String Array, so need string[] variable not list
string[] previousRow = null ;
string[] currentRow;
string[] rowDifferences ;
// to store the result
List<string[]> resultingDataset = new List<string[]>();
foreach (var item in datatable)
{
if (previousRow == null)
{
previousRow = item;
resultingDataset.Add(previousRow); // add first item to list
continue;
}
currentRow = item;
// check and replace with "-" if elment exist in previous
rowDifferences = currentRow.Select((x, i) => currentRow[i] == previousRow[i] ? "-" : currentRow[i]).ToArray();
resultingDataset.Add(rowDifferences);
// make current as previos
previousRow = item;
}
return resultingDataset;
}
check this dotnetfiddle
private static List<List<string>> FilterData(List<List<string>> datatable)
{
var result = new List<List<string>>();
for(var rowindex = 0; rowindex < datatable.Count; rowindex++)
{
// Clone the string list
var refrow = datatable[rowindex]
.Select(item => (string)item.Clone()).ToList();
result.Add(refrow);
// First row will not get modify anyway
if (rowindex == 0) continue;
var row = result[rowindex];
// previous row of result has changed to "-", so use the original row to compare
var prevrow = datatable[rowindex - 1];
for(var columnindex = 0; columnindex < row.Count; columnindex++)
{
if (row[columnindex] == prevrow[columnindex])
row[columnindex] = "-";
}
}
return result;
}
fiddle
public static List<List<T>> RemoveDuplicates<T>(this List<List<T>> items, T replacedValue) where T: class
{
List<List<T>> ret = items;
items.ForEach(m=> {
var ind = items.IndexOf(m);
if(ind==0)
{
ret.Add(items.FirstOrDefault());
}
else
{
var prevItem = items.Skip(items.IndexOf(m)-1).FirstOrDefault();
var item = new List<T>();
for(var a = 0; a < prevItem.Count; a++)
{
item.Add(prevItem[a] == m[a]? replacedValue : m[a]);
}
ret.Add(item);
}
});
return ret;
}
How to use it:
var items = new List<List<string>>{
new List<string>{ "1", "4", "6", "8" },
new List<string>{ "1", "2", "6", "8" },
new List<string>{ "2", "4", "6", "8" },
new List<string>{ "3", "4", "5", "7" }
};
var result = items.RemoveDuplicates("-");
dotNetFiddle: https://dotnetfiddle.net/n36p64
I have two lists like below in C#.
List 1 = [{Item="A",position =1},{Item="B",position =2},{Item="A",position =3}]
List 2 = [{Item="AA",position =1},{Item="BB",position =2},{Item="AC",position =3}]
Now i want to remove duplicate values in the List 1 and that position should be removed in the List 2.
Example o/p
List 1 = [{Item="A",position =1},{Item="B",position =2}]
List 2 = [{Item="AA",position =1},{Item="BB",position =2}]
Can any one help me. Thanks.
List<string> lst1 = new List<string> { "A", "B", "A" };
List<string> lst2 = new List<string> { "AA", "BB", "AC" };
HashSet<string> seen = new HashSet<string>();
for (int i = 0; i < lst1.Count; i++) {
if (!seen.Add(lst1[i])) {
lst1.RemoveAt(i);
lst2.RemoveAt(i);
i--;
}
}
I used a HashSet to "save" the "already seen" elements of lst1 and then simply cycle the lst1 and remove the duplicate elements. HashSet.Add returns true if the HashSet doesn't already have an element, false if it already has it.
It isn't exactly clear what you want/what you have, but here there is the solution for another possible use case:
public class MyObject {
public string Item;
public int Position;
}
List<MyObject> lst1 = new List<MyObject> {
new MyObject { Item = "A", Position = 1 },
new MyObject { Item = "B", Position = 2 },
new MyObject { Item = "A", Position = 3 },
};
List<MyObject> lst2 = new List<MyObject> {
new MyObject { Item = "AA", Position = 1 },
new MyObject { Item = "BB", Position = 2 },
new MyObject { Item = "AC", Position = 3 },
};
HashSet<string> seen = new HashSet<string>();
HashSet<int> toBeDeleted = new HashSet<int>();
for (int i = 0; i < lst1.Count; i++) {
if (!seen.Add(lst1[i].Item)) {
toBeDeleted.Add(lst1[i].Position);
lst1.RemoveAt(i);
i--;
}
}
if (toBeDeleted.Count > 0) {
for (int i = 0; i < lst2.Count; i++) {
if (toBeDeleted.Contains(lst2[i].Position)) {
lst2.RemoveAt(i);
i--;
}
}
// or equivalent and shorter, without the for cycle
//lst2.RemoveAll(x => toBeDeleted.Contains(x.Position));
}
In this case in a first pass on lst1 we remove the duplicate items (as seen in the first example) and "save" the Positions that need to be deleted in the HashSet<int> tobedeleted and then we do a second pass on lst2 to remove the elements that need deleting.
Much not clear what you want do, but I try with this:
var filteredList1 = list1.GroupBy(x => x.Item).Select(g => g.First()).ToList();
var removeElements = list2.Where(f => !filteredList1.Any(t => t.Position == f.Position)).ToList();
removeElements.ForEach(x => list2.Remove(x));
This question already has answers here:
Split List into Sublists with LINQ
(34 answers)
Closed 8 years ago.
I have a List<string> and I want to take groups of 5 items from it. There are no keys or anything simple to group by...but it WILL always be a multiple of 5.
e.g.
{"A","16","49","FRED","AD","17","17","17","FRED","8","B","22","22","107","64"}
Take groups of:
"A","16","49","FRED","AD"
"17","17","17","FRED","8"
"B","22","22","107","64"
but I can't work out a simple way to do it!
Pretty sure it can be done with enumeration and Take(5)...
You can use the integer division trick:
List<List<string>> groupsOf5 = list
.Select((str, index) => new { str, index })
.GroupBy(x => x.index / 5)
.Select(g => g.Select(x => x.str).ToList())
.ToList();
List<List<string>> result = new List<List<string>>();
for(int i = 0; i < source.Count; i += 5 )
result.Add(source.Skip(i).Take(5).ToList());
Like this?
In common programming syntax:
public List<List<string>> Split(List<string> items, int chunkSize = 5)
{
int chunkCount = items.Count/chunkSize;
List<List<string>> result = new List<List<string>>(chunkCount);
for (int i = 0; i < chunkCount; i++ )
{
result.Add(new List<string>(chunkSize));
for (int j = i * chunkSize; j < (i + 1) * chunkSize; j++)
{
result[i].Add(items[j]);
}
}
return result;
}
It's O((N/ChunkSize) x ChunkSize) = O(N), that is linear.
I recommend Batch method from MoreLINQ library:
var result = list.Batch(5).ToList();
Use Take() and Skip() to achieve this:
List<string> list = new List<string>() { "A", "16", "49", "FRED", "AD", "17", "17", "17", "FRED", "8", "B", "22", "22", "107", "64" };
List<List<string>> result = new List<List<string>>();
for (int i = 0; i < list.Count / 5; i++)
{
result.Add(list.Skip(i * 5).Take(5).ToList());
}
If you need performance or cannot use linq cause of your .net version here is a simple solution with O(n)
private List<List<string>> SplitList(List<string> input, int size = 5)
{
var result = new List<List<string>>();
for (int i = 0; i < input.Count; i++)
{
var partResult = new List<string>();
while (true)
{
// save n items
partResult.Add(input[i]);
if ((i+1) % size == 0)
{
break;
}
i++;
}
result.Add(partResult);
}
return result;
}
You can use this function:
public IEnumerable<string[]> GetChunk(string[] input, int size)
{
int i = 0;
while (input.Length > size * i)
{
yield return input.Skip(size * i).Take(size).ToArray();
i++;
}
}
it returns you chunks from your list
you can check it like
var list = new[]
{
"A", "16", "49", "FRED", "AD", "17", "17", "17", "FRED", "8", "B", "22", "22", "107", "64"
};
foreach (var strings in GetChunk(list, 5))
{
Console.WriteLine(strings.Length);
}
I got a list:
var x = new List<string>(){"a","b","c"}
I am looking for an pretty easy way to change all items after a
example:
var x = new List<string>(){"a","b","c"}
var y = new List<string>(){"d","e","f"}
x.addAfterFirst(y);
result x= "a","d","e","f"
I know that' x.Skip(1)' can return me the info. I need to set it.
You can use the Take Extension Method to take the first n items from x and concat them with y using the Concat Extension Method:
List<string> x = new List<string> { "a", "b", "c" };
List<string> y = new List<string> { "d", "e", "f" };
int n = 1;
List<string> result = x.Take(n).Concat(y).ToList();
// result == { "a", "d", "e", "f" }
If you want to modify x in-place instead of creating a new list, you can use the RemoveRange Method to remove all items after the first n items, and the AddRange Method to append y to x:
List<string> x = new List<string> { "a", "b", "c" };
List<string> y = new List<string> { "d", "e", "f" };
int n = 1;
x.RemoveRange(n, x.Count - n);
x.AddRange(y);
// x == { "a", "d", "e", "f" }
Make use of InsertRange will do you task
var x = new list<string>(){"a","b","c"}
var y = new list<string>(){"d","e","f"}
x.InsertRange(2,y);
Edit
now if you want to remove element
var x = new list<string>(){"a","b","c"};
int xlength = x.Count() - 1;
var y = new list<string>(){"d","e","f"};
int ylength = y.Count() - 1;
x.InsertRange(2,y);
x.RemoveRang( 2 + ylength, xlength- 2);
Your result doesn't match the full description
Are you wishing to insert or replace
Are you needing to modify the existing collection or could you accept a new collection?
All examples use the following initialization
var insertIndex=1;
var x = new List<string>(){"a","b","c"};
var y = new List<string>(){"d","e","f"};
New Collection Replace
var result=x.Take(insertIndex).Concat(y).ToList();
New Collection Insert
var result=x.Take(insertIndex).Concat(y).Concat(x.Skip(insertIndex)).ToList();
Modify Collection Replace
x.RemoveRange(insertIndex,x.Count-insertIndex);
x.AddRange(y);
Modify Collection Insert
x.InsertRange(insertIndex,y);
Non-LINQ extention way:
int i;
for (i=0;i < y.Count;i++)
{
if (i+1 < x.Count)
x[i+1] = y[i];
else
x.Add(y[i]);
}
//If you dont want trailing elements to remain in x
for (;i < x.Count;i++)
x.RemoveAt(i);