Splitting a list c# - c#

Hi I'm a little bit stuck in C#. I'm new on it.
This is my problem:
I have a list made up of 63 double numbers (let's call it "big list").
I want to split this list in 6 list with the following rule:
The first list consists of the first 8 elements of the big list;
The second list goes from the 9th element of the big list to the (9+8=17th) element of the big list;
The third list goes from the 18th element of the big list to the (18+8+1=27th) element of the big list;
The fourth list goes from the 28th element of the big list to the (28+8+2=38th) element of the big list;
The fifth list goes from the 39th element of the big list to the (39+8+3=50th) element of the big list;
The sixth list goes from the 51th element of the big list to the (51+8+4=63th) element of the big list;
How can I do it? thanks a lot in advance for your help!
i've tried in this way but it gives me error "cannot apply indexing with [] to an expression of type method group"
List listsplitted = new List();
for (int i = 0; i < 6; i++)
{
for (int j = 8; j < 8 + i + 1; j++)
{
Listsplitted[i] = biglist.Take[j];
}
}

It is a very simple approach with the IEnumerable extensions Skip and Take
List<double> first = bigList.Take(8).ToList();
List<double> second = bigList.Skip(8).Take(8).ToList();
List<double> third = bigList.Skip(16).Take(9).ToList();
List<double> fourth = bigList.Skip(25).Take(10).ToList();
List<double> fifth = bigList.Skip(35).Take(11).ToList();
// The last one is without Take to get every remaining element
List<double> sixth = bigList.Skip(46).ToList();
Of course you should check if the indexes are correct for your requirements. These indexes doesn't skip any elements from your bigList
You can make this approach more generic with something like this
void Main()
{
var bigList = GetYourBigList();
List<Tuple<int, int>> positions = new List<Tuple<int, int>>
{
new Tuple<int, int>(0,8),
new Tuple<int, int>(8,8),
new Tuple<int, int>(16,9),
new Tuple<int, int>(25,10),
new Tuple<int, int>(35,11),
new Tuple<int, int>(46,13)
};
List<List<int>> result = SplitTheList(bigList, positions);
foreach (var list in result)
{
foreach (var temp in list)
Console.WriteLine(temp);
Console.WriteLine("--------------------");
}
}
List<List<int>> SplitTheList(List<int> r, List<Tuple<int, int>> positions)
{
List<List<int>> result = new List<List<int>>();
foreach(var x in positions)
result.Add(r.Skip(x.Item1).Take(x.Item2).ToList());
return result;
}

You can do it using GetRange function:
List<double> part1= big_list.GetRange(0, 8);//Retrieves 8 items starting with index '0'
List<double> part2= big_list.GetRange(8, 9);//Retrieves 9 items starting with index '8'
Or if you don't want to give different names to all parts, you can create a list of lists:
List<List<double>> listoflists = new List<List<double>>();
listoflists.Add(big_list.GetRange(0, 8));//Retrieves 8 items starting with index '0'
listoflists.Add(big_list.GetRange(8, 9));//Retrieves 9 items starting with index '8'
for(int i=0; i<listoflists.Count;i++){
for(int j=0; j<listoflists[i].Count; j++){
Console.Write(listoflists[i][j] + " ");
}
Console.WriteLine();
}

if you are insisting on do the operation in one single for statement you can use the following code
const int arrSize = 6;
var splitedLists = new List<List<int>>(arrSize);
var defaultTake = 8;
var defaultSkip = 0;
for (var i = 1; i <= arrSize; i++)
{
if (i >= 3)
defaultSkip--;
splitedLists.Add(array.Skip(defaultSkip).Take(defaultTake + 1).ToList());
if (i >= 2)
defaultTake++;
defaultSkip = defaultSkip + defaultTake + 1;
}

If you can replace the list with an array, you can do without copying the data. You can use ArraySegment (or Span/Memory in newer versions of the language) to do this.
var array = Enumerable.Range(0, 63).Select(i => (double)i).ToArray();
var splitted = new List<ArraySegment<double>>();
int offset = 0;
int count = 8;
for (int i = 0; i < 6; i++)
{
splitted.Add(new ArraySegment<double>(array, offset, count));
offset += count;
count++;
}
// see what we have
foreach (var seg in splitted)
Console.WriteLine(seg.Offset + " " + seg.Count);
// work with segments
var segment = splitted[3];
segment[5] = 555555;
// the main array has also changed
Console.WriteLine(string.Join(" ", array));
Note that the segments do not store copies of the data, but refer to the data in the main array.

Related

Remove second occurrence of value from array C#

Instead of removing the first occurrence of a duplicated value, as my code currently does, how can I get it to delete the second occurrence instead?
namespace deletenumber
{
class Program
{
public static void Main(String[] args)
{
Random r = new Random();
int[] a = new int[10];
for (int i = 0; i < 10; i++)
a[i] = r.Next(1, 100);
for (int i = 0; i < 10; i++)
Console.WriteLine(" a [" + i + "] = " + a[i]);
Console.WriteLine();
Console.ReadLine();
Console.WriteLine("What number do you want to delete?");
int item = Convert.ToInt32(Console.ReadLine());
Console.WriteLine();
int index = Array.IndexOf(a, item);
a = a.Where((b, c) => c != index).ToArray();
Console.WriteLine(String.Join(", ", a));
Console.ReadLine();
}
}
}
I'm not sure why exactly you might want to delete only the second occurrence because there should be no matter which one of the duplicates is removed, correct?
Anyway, there are several ways of achieving what you want.
I will not directly write a solution here, but will propose the methods you can use in order to achieve what you want:
Array.LastIndexOf
Use the same IndexOf method again to find the second occurrence, by starting the search from the previous occurrence (myArray.IndexOf("string", last_indexof_index);)
Generally, consider using a HashSet<T> (official docs here) if you want to have a collection of unique elements.
You can also convert your existing collection to HashSet<int>:
int[] a = new int[10];
var set = new HashSet<int>(a);
You could convert your array to a List and then just remove the index before casting it back to an array:
var list = new List<int>(a);
list.RemoveAt(index);
a = list.ToArray();

Convert Ienumerable<int> to array and add to list C#

I have a simple code:
List<int[]> list = new List<int[]>();
for (int i = 0; i < x; i++)
{
var vec = vector.Skip(index).Take(width);
var v = vec.ToArray();
list.Add(v);
index = index + width;
}
string toDisplay = string.Join(Environment.NewLine, list);
MessageBox.Show(toDisplay);
This is vector:
int[] vector = new int[length];
Random z = new Random();
for (int i = 0; i < length; i++)
{
vector[i] = z.Next(-100, 100);
}
What I want to do is to slice my vector on smaller vectors and add them to list of int. Using my code I only get System.Int32[] in MessageBox. I know that maybe my code it's not the right way. I barely know C#.
How can I do this in other way?
Apparently you mean to slice the initial array into smaller chunks and display them in a single line. This can be done using Linq as follows.
var StringToDisplay
= String.Join(Environment.NewLine, list.Select(iList => String.Join(",", iList)));
List<int[]> list is a list of arrays, not numbers. Calling ToString() on an array uses Object.ToString() which returns the object's (array's) type.
If you want to display a list of pages, you should change your string construction code to work with the inner arrays. One option is to use LINQ :
var lines=from page in list
select string.Join(",", page);
string toDisplay = string.Join(Environment.NewLine, lines);
It's better to use StringBuilder though, to avoid generating a lot of temporary strings:
var builder=new StringBuilder();
foreach(var page in list)
{
builder.AppendLine(string.Join(",", page));
}
string toDisplay = builder.ToString();
If you want a list of numbers change the list type to List. You can also simplify the code by using AddRange, eg :
List<int> list = new List<int>();
for (int i = 0; i < x; i++)
{
var vec = vector.Skip(index).Take(width);
list.AddRange(vec);
index = index + width;
}
string toDisplay = string.Join(Environment.NewLine, lines);

How to create a string set with multiple list?

User can pass any number of list with same number of elements in it. Example- user has passed below 3 (could be dynamic with same number of elements in it) list -
hospitalId - H11, H12, H13...n
patientId - P11, P12, P13...n
statusId - S11, S13, S11...n
What is the efficient way of creating a set out of it and storing it as a string in below format? Need a c# code for it.
expected output -
"((H11,P11, S11), (H12, P12, S13), (H13, P13, S11))"
You should iterate through your list and append them index wise to prepare the result.
StringBuilder builder = new StringBuilder();
builder.Append("(");
for(var index = 0; index < n; index++)
{
builder.AppendFormat("({0}, {1}, {2})", hospitalId[index], patientId[index], statusId[index]);
}
builder.Append(")");
var result = builder.ToString();
If you have n number of List<T> items with the same length, a basic loop will do the trick. Here's a version as an extension method that will take any number of lists as an input:
public static IEnumerable<IEnumerable<T>> ZipMultiple<T>(this List<List<T>> source)
{
var counts = source.Select(s => s.Count).Distinct();
if (counts.Count() != 1)
{
throw new ArgumentException("Lists aren't the same length");
}
for (var i = 0; i < counts.First(); i++)
{
var item = new List<T>();
for (var j = 0; j < source.Count; j++)
{
item.Add(source[j][i]);
}
yield return item;
}
}
After that, it's pretty simple to convert the result into a string in another loop, or you can do it as a single liner:
var zipped = lists.ZipMultiple();
var output = $"({string.Join(", ", zipped.Select(x => $"({string.Join(",", x)})"))})";

How to populate two separate arrays from one comma-delimited list?

I have a comma delimited text file that contains 20 digits separated by commas. These numbers represent earned points and possible points for ten different assignments. We're to use these to calculate a final score for the course.
Normally, I'd iterate through the numbers, creating two sums, divide and be done with it. However, our assignment dictates that we load the list of numbers into two arrays.
so this:
10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85
becomes this:
int[10] earned = {10,20,30,40,45,50,20,45,85};
int[10] possible = {10,20,35,50,50,50,20,90,85};
Right now, I'm using
for (x=0;x<10;x++)
{
earned[x] = scores[x*2]
poss [x] = scores[(x*2)+1]
}
which gives me the results I want, but seems excessively clunky.
Is there a better way?
The following should split each alternating item the list into the other two lists.
int[20] scores = {10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85};
int[10] earned;
int[10] possible;
int a = 0;
for(int x=0; x<10; x++)
{
earned[x] = scores[a++];
possible[x] = scores[a++];
}
You can use LINQ here:
var arrays = csv.Split(',')
.Select((v, index) => new {Value = int.Parse(v), Index = index})
.GroupBy(g => g.Index % 2,
g => g.Value,
(key, values) => values.ToArray())
.ToList();
and then
var earned = arrays[0];
var possible = arrays[1];
Get rid of the "magic" multiplications and illegible array index computations.
var earned = new List<int>();
var possible = new List<int>();
for (x=0; x<scores.Length; x += 2)
{
earned.Add(scores[x + 0]);
possible.Add(scores[x + 1]);
}
This has very little that would need a text comment. This is the gold standard for self-documenting code.
I initially thought the question was a C question because of all the incomprehensible indexing. It looked like pointer magic. It was too clever.
In my codebases I usually have an AsChunked extension available that splits a list into chunks of the given size.
var earned = new List<int>();
var possible = new List<int>();
foreach (var pair in scores.AsChunked(2)) {
earned.Add(pair[0]);
possible.Add(pair[1]);
}
Now the meaning of the code is apparent. The magic is gone.
Even shorter:
var pairs = scores.AsChunked(2);
var earned = pairs.Select(x => x[0]).ToArray();
var possible = pairs.Select(x => x[1]).ToArray();
I suppose you could do it like this:
int[] earned = new int[10];
int[] possible = new int[10];
int resultIndex = 0;
for (int i = 0; i < scores.Count; i = i + 2)
{
earned[resultIndex] = scores[i];
possible[resultIndex] = scores[i + 1];
resultIndex++;
}
You would have to be sure that an equal number of values are stored in scores.
I would leave your code as is. You are technically expressing very directly what your intent is, every 2nd element goes into each array.
The only way to improve that solution is to comment why you are multiplying. But I would expect someone to quickly recognize the trick, or easily reproduce what it is doing. Here is an excessive example of how to comment it. I wouldn't recommend using this directly.
for (x=0;x<10;x++)
{
//scores contains the elements inline one after the other
earned[x] = scores[x*2] //Get the even elements into earned
poss [x] = scores[(x*2)+1] //And the odd into poss
}
However if you really don't like the multiplication, you can track the scores index separately.
int i = 0;
for (int x = 0; x < 10; x++)
{
earned[x] = scores[i++];
poss [x] = scores[i++];
}
But I would probably prefer your version since it does not depend on the order of the operations.
var res = grades.Select((x, i) => new {x,i}).ToLookup(y=>y.i%2, y=>y.x)
int[] earned = res[0].ToArray();
int[] possible = res[1].ToArray();
This will group all grades into two buckets based on index, then you can just do ToArray if you need result in array form.
here is an example of my comment so you do not need to change the code regardless of the list size:
ArrayList Test = new ArrayList { "10,10,20,20,30,35,40,50,45,50,45,50,50,50,20,20,45,90,85,85" };
int[] earned = new int[Test.Count / 2];
int[] Score = new int[Test.Count / 2];
int Counter = 1; // start at one so earned is the first array entered in to
foreach (string TestRow in Test)
{
if (Counter % 2 != 0) // is the counter even
{
int nextNumber = 0;
for (int i = 0; i < Score.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(Score[i])))
{
nextNumber = i;
break;
}
}
Score[nextNumber] = Convert.ToInt32(TestRow);
}
else
{
int nextNumber = 0;
for (int i = 0; i < earned.Length; i++) // this gets the posistion for the next array entry
{
if (String.IsNullOrEmpty(Convert.ToString(earned[i])))
{
nextNumber = i;
break;
}
}
earned[nextNumber] = Convert.ToInt32(TestRow);
}
Counter++
}

Find all subsets of a list

I have a list and I need to output each subset of the list
for example a b c d e
would output to
a
b
c
d
e
ab
ac
ad
ae
abc
abd
abe
bcd
bce
....
abcde
I believe the correct term is combination no element should be duplicated on the same line
I was going to attempt this with a series of loops but im not even sure wehre to start
any suggestions?
This will generate the set you want, but in a different order (I sort by alphabet at the end, you'd want to sort by length as well).
You'll end up with:
a
ab
abc
abcd
abcde
abce
...
d
de
e
So, every possible subset (aside from the empty string), while maintaining the order of the original list.
The idea is to add each element to to a growing list. With every new element, add it first, and then add it to all existing elements.
So, start with 'a'.
Go on to 'b'. Add it to the list. We now have {'a', 'b'}.
Add it to existing elements, so we have 'ab'. Now we have {'a', 'b', 'ab'}.
Then 'c', and add it to existing elements to get 'ac', 'bc', 'abc': {'a', 'b', 'ab', 'c', 'ac', 'bc', abc'}. So forth until we're done.
string set = "abcde";
// Init list
List<string> subsets = new List<string>();
// Loop over individual elements
for (int i = 1; i < set.Length; i++)
{
subsets.Add(set[i - 1].ToString());
List<string> newSubsets = new List<string>();
// Loop over existing subsets
for (int j = 0; j < subsets.Count; j++)
{
string newSubset = subsets[j] + set[i];
newSubsets.Add(newSubset);
}
subsets.AddRange(newSubsets);
}
// Add in the last element
subsets.Add(set[set.Length - 1].ToString());
subsets.Sort();
Console.WriteLine(string.Join(Environment.NewLine, subsets));
if all you need are combinations of the elements in your original list, you can transform the problem into the following: you have a bit array of size N, and you want to find all possible choices for the elements of the array. For example, if your original list is
a b c d e
then your array can be
0 1 0 0 0
which results in an output of
b
or the array can be
1 0 1 1 0
which returns
acd
this is a simple recursion problem that can be solved in an O(2^n) time
edit adding pseudo-code for recursion algorithm:
CreateResultSet(List<int> currentResult, int step)
{
if (the step number is greater than the length of the original list)
{
add currentResult to list of all results
return
}
else
{
add 0 at the end of currentResult
call CreateResultSet(currentResult, step+1)
add 1 at the end of currentResult
call CreateResultSet(currentResult, step+1)
}
}
for every item in the list of all results
display the result associated to it (i.e. from 1 0 1 1 0 display acd)
This will work with any collection. I modified #Sapp's answer a little
static List<List<T>> GetSubsets<T>(IEnumerable<T> Set)
{
var set = Set.ToList<T>();
// Init list
List<List<T>> subsets = new List<List<T>>();
subsets.Add(new List<T>()); // add the empty set
// Loop over individual elements
for (int i = 1; i < set.Count; i++)
{
subsets.Add(new List<T>(){set[i - 1]});
List<List<T>> newSubsets = new List<List<T>>();
// Loop over existing subsets
for (int j = 0; j < subsets.Count; j++)
{
var newSubset = new List<T>();
foreach(var temp in subsets[j])
newSubset.Add(temp);
newSubset.Add(set[i]);
newSubsets.Add(newSubset);
}
subsets.AddRange(newSubsets);
}
// Add in the last element
subsets.Add(new List<T>(){set[set.Count - 1]});
//subsets.Sort();
return subsets;
}
**And then if I have a set of strings I will use it as:
Here is some code I made. It constructs a list of all possible strings from an alphabet, of lengths 1 to maxLength: (in other words, we are calculating the powers of the alphabet)
static class StringBuilder<T>
{
public static List<List<T>> CreateStrings(List<T> alphabet, int maxLength)
{
// This will hold all the strings which we create
List<List<T>> strings = new List<List<T>>();
// This will hold the string which we created the previous time through
// the loop (they will all have length i in the loop)
List<List<T>> lastStrings = new List<List<T>>();
foreach (T t in alphabet)
{
// Populate it with the string of length 1 read directly from alphabet
lastStrings.Add(new List<T>(new T[] { t }));
}
// This holds the string we make by appending each element from the
// alphabet to the strings in lastStrings
List<List<T>> newStrings;
// Here we make string2 for each length 2 to maxLength
for (int i = 0; i < maxLength; ++i)
{
newStrings = new List<List<T>>();
foreach (List<T> s in lastStrings)
{
newStrings.AddRange(AppendElements(s, alphabet));
}
strings.AddRange(lastStrings);
lastStrings = newStrings;
}
return strings;
}
public static List<List<T>> AppendElements(List<T> list, List<T> alphabet)
{
// Here we just append an each element in the alphabet to the given list,
// creating a list of new string which are one element longer.
List<List<T>> newList = new List<List<T>>();
List<T> temp = new List<T>(list);
foreach (T t in alphabet)
{
// Append the element
temp.Add(t);
// Add our new string to the collection
newList.Add(new List<T>(temp));
// Remove the element so we can make another string using
// the next element of the alphabet
temp.RemoveAt(temp.Count-1);
}
return newList;
}
}
something on the lines of an extended while loop :
<?
$testarray[0] = "a";
$testarray[1] = "b";
$testarray[2] = "c";
$testarray[3] = "d";
$testarray[4] = "e";
$x=0;
$y = 0;
while($x<=4) {
$subsetOne[$x] .= $testarray[$y];
$subsetOne[$x] .= $testarray[$x];
$subsetTwo[$x] .= $testarray[$y];
$subsetTwo[$x] .= $subsetOne[$x];
$subsetThree[$x] = str_replace("aa","ab",$subsetTwo[$x]);
$x++;
}
?>

Categories