How to make an Enumerable Range List of Lists? - c#

I can make a List of chars like this:
List<char> letter = Enumerable.Range(0, 10)
.Select(i => '\0')
.ToList();
And a List of int? like this:
List<int?> number = Enumerable.Range(0, 10)
.Select(i => (int?)i)
.ToList();
And call them by letter[1] = 'a' and number[1] = 5.
How can I make a List (or HashSet) of 10 List<char>'s?
Something like:
List<char> myList = Enumerable.Range(0, 10)
.Select(i => List<char> i)
.ToList();
myList[1], myList[2], myList[3]
I want to loop through and add items to each list.
for (int i = 0; i < 10; i++)
{
myList[i].Add(letter[i]);
}

You can combine your two approaches as follows:
List<List<char>> myList = Enumerable.Range(0, 10)
.Select(i => Enumerable.Range(0, 10).Select(c => '\0').ToList())
.ToList();

Related

C# Linq Find all indexes of item in List<int> within another List<int>

I have a List looks like:
List<int> List1= new List<int>(){3,4,5};
and another looks like:
List<int> List2 = new List<int>(){1,2,3,4,5,6};
How can I use Linq to get an array of all of the indices of List1 from List2 like below:
var ResultList = {2,3,4};
var ResultList = List1.Select(x => List2.IndexOf(x));
This is a longer solution but prevents a nested loop through the array which may be faster if the arrays are huge (but slower if the arrays are small).
List<int> List1= new List<int>(){3,4,5};
List<int> List2 = new List<int>(){1,2,3,4,5,6};
var lookup = new Dictionary<int, int>();
for(var i=0; i<List2.Count; i++) {
lookup[List2[i]] = i;
}
List<int> Result = List1.Select(i => {
int index;
return lookup.TryGetValue(i, out index) ? index : -1;
}).ToList();
You can also do the overloaded version of Select statement to select the Value and return the Index:
var result = List2.Select((a, b) => new {Value = a, Index = b})
.Where(x => List1.Any(d => d == x.Value))
.Select(c => c.Index).ToArray();
If your List2 contains more than one instance of a List1 value (or Equality) type, then you can use the indexed overload of Select to find all the duplicates:
var List1= new List<int>(){3,4,5};
var List2 = new List<int>(){1,2,3,4,5,6,1,2,3,5};
var result = List2.Select((x, idx) => Tuple.Create(x, idx))
.Where(t => List1.Contains(t.Item1))
.Select(x => x.Item2)
// 2,3,4,8,9
or better, using C#7 Value Tuples
List2.Select((x, idx) => (X:x, Idx:idx))
.Where(t => List1.Contains(t.X))
.Select(x => x.Idx);
(.IndexOf returns just the first index found in the target)

grouping 100 number in array into 4 group in c# [duplicate]

This question already has answers here:
Split a collection into `n` parts with LINQ? [duplicate]
(21 answers)
Closed 6 years ago.
Hi everybody I have an array with 1 to 100 number and I want to group it to four group that each group have 25 number. How can i do it. Thanks
static void Main(string[] args)
{
int[] array = new int[101];
for (int i = 1; i <= 100; i++)
{
array[i] = i; Console.WriteLine(array[i]);
}
var s = array.GroupBy(x => array.Length % 25).Select(d => new { k = d.Key, v = d.OrderBy(f => f) });
foreach (var item in s)
{
Console.WriteLine($"{item.k}");
foreach (var item2 in item.v)
{
Console.WriteLine($"\t{item2}");
}
Console.WriteLine("------------");
}`enter code here`
Your question is vague; there're many ways to group by the array:
int[] array = Enumerable
.Range(1, 100)
.ToArray();
Possible groupings (by index):
int[][] result = array
.Select((item, index) => new {
item = item,
index = index })
.GroupBy(chunk => chunk.index % 4)
.Select(chunk => chunk
.Select(x => x.item)
.ToArray())
.ToArray();
Or
int[][] result = array
.Select((item, index) => new {
item = item,
index = index })
.GroupBy(chunk => chunk.index / 25)
.Select(chunk => chunk
.Select(x => x.item)
.ToArray())
.ToArray();
Or grouping by value
int[][] result = array
.GroupBy(item => item % 4)
.Select(chunk => chunk
.ToArray())
.ToArray();
To print out the result (and test grouping) use string.Join:
string report = string.Join(Environment.NewLine, result
.Select(line => string.Join(" ", line
.Select(item => string.Format("{0,3}", item)))));
Console.Write(report);

Select last wrong item from the list

I have a list with items, that have a Time property. If I want to select all items where Time is equal or bigger then some startTime, then I write something like this:
var newList = list.Where(i => (i.Time >= startTime));
But now I also want to get the last item, where the time is smaller than startTime. Is there a better way to implement this?
For example I have list where items have Time from this list:
[5:32, 5:46, 5:51, 6:07, 6:11, 6:36]
We specify a startTime as 6:00.
Now we want to get this times:
[5:51, 6:07, 6:11, 6:36]
Getting the whole List at once:
var newList = list
.OrderByDescending(i => i.Time)
.Take(list.Count(j => j.Time >= startTime) + 1)
.OrderBy(k => k.Time); //Optional
With Cognition's suggestion:
var newList = list
.OrderBy(i => i.Time)
.Skip(list.Count(j => j.Time < startTime - 1));
var result=list
.Where(i=>i.Time<startTime)
.OrderBy(i=>i.Time)
.Last()
.Concat(list
.OrderBy(i=>i.Time)
.Where(i=>i.Time>=startTime)
);
or
var result=list
.OrderBy(i=>i.Time)
.Last(i=>i.Time<startTime)
.Concat(list
.OrderBy(i=>i.Time)
.Where(i=>i.Time>=startTime)
);
var smallerThan = list
.Where(i => i.Time < startTime)
.OrderByDescending(o => o.Time)
.Take(1)
.Concat(list.Where(i => i.Time => startTime));
As your list is in order of the property you want to find, you can do something along the lines of
List<int> things = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8 };
int threshold = 4;
var newThings = things.Skip(things.FindIndex(x => x >= threshold) - 1);
Console.WriteLine(string.Join(", ", newThings));
Which outputs
3, 4, 5, 6, 7, 8
Extending it to use a class with a Time property which happens to be a TimeSpan:
class Z
{
public TimeSpan Time { get; set; }
};
class Program
{
static void Main(string[] args)
{
Random rand = new Random();
List<Z> zs = new List<Z>();
for (int i = 0; i < 10; i++)
{
zs.Add(new Z { Time = new TimeSpan(i, rand.Next(0,61), rand.Next(0,61)) });
}
TimeSpan threshold = new TimeSpan(4,0,0);
var newThings = zs.Skip(zs.FindIndex(x => x.Time >= threshold) - 1);
Console.WriteLine(string.Join(", ", newThings.Select(x => x.Time.ToString("c"))));
Console.ReadLine();
}
}
Sample output:
03:03:57, 04:09:37, 05:14:44, 06:58:55, 07:40:33, 08:37:06, 09:10:06
Many of the answers seem to require a descending orderby. But you can easily avoid this with a clean one liner and good efficiency:
var newList = list.Skip(list.Count(j => j.Time < startTime) - 1);
var newList = list
.Where(i => (i.Time >= startTime))
.ToList()
.Add(list
.Where(i => (i.Time < startTime))
.OrderByDescending(o => o.Time)
.FirstOrDefault()
)
int lastItemIndex = list.OrderBy(D => D.TimeOfDay).ToList()
.FindLastIndex(D => D.TimeOfDay < startTime);
var newList = list.Where(D => list.IndexOf(D) > lastItemIndex);

Counting letter frequencies

I'm reading in a text file using StreamReader to the program. I need to record the frequency of each letter in the string into an array (where index 0 would be A, and so on). What's the simplest approach for this?
Edit: I had this originally, until I realized it was completely wrong.
int counter = 0;
int[] freq = new int[26]; // create frequency array
// counts frequency
while (counter < inValue.Length)
{
int A = 65; // ASCII value for "A"
char x = char.Parse(inValue.Substring(counter, 1)); // get individual characters from string
int s = (int)x; // cast character to integer value
if (s == A + counter)
freq[counter]++;
counter++;
}
Where inValue is the text file StreamReader reads into the program.
var freqs = File.ReadAllText("myfile.txt")
.Where(c => Char.IsLetter(c))
.GroupBy(c => c)
.ToDictionary(g => g.Key, g => g.Count());
This should give you a Dictionary of characters and their count.
Update:
If you want case insensitive counts, just change the GroupBy:
.GroupBy(c => Char.ToUpper(c)) // instead of .GroupBy(c => c)
And in my opinion a dictionary is better than an array in this case because the character that the "count" belongs to is not just implied by the index; instead, it is an explicit key. This makes lookups easier because you don't have to convert the character to an index. Additionally, this makes it more flexible when adding internationalization support. However, if you absolutely need an array, it is a simple change:
var freqs = File.ReadAllText("myfile.txt")
.Where(c => Char.IsLetter(c))
.GroupBy(c => c)
.OrderBy(g => g.Key)
.Select(g => g.Count())
.ToArray()
You can try something like this. This worked for me but I didnt used StreamReader:-
int[] c = new int[(int)char.MaxValue];
string s = File.ReadAllText("text.txt");
foreach (char t in s)
{
c[(int)t]++;
}
for (int i = 0; i < (int)char.MaxValue; i++)
{
if (c[i] > 0 &&
char.IsLetterOrDigit((char)i))
{
Console.WriteLine("Letter: {0} Frequency: {1}",(char)i, c[i]);
}
}
A few modifications to your code will make it work, assuming that you only want to count the letters 'A' through 'Z':
int counter = 0;
int[] freq = new int[26]; // create frequency array
// counts frequency
while (counter < inValue.Length)
{
char c = invalue[counter];
if (c >= 'A' && c <= 'Z')
{
++freq[(int)c - 65]
}
++counter;
}
If you want to count lower case letters as well, then change the first line in the loop to:
char c = char.ToUpper(invalue[counter]);
I spent quite a while to figure out this Linq which will result in the exact same array you want:
int[] occurance = File.ReadAllText("myfile.txt")
.Where(c => char.IsLetter(c))
.Select(c => (int)char.ToUpperInvariant(c) - 65)
.GroupBy(a => a)
.ToDictionary(a => a.Key, a => a.Count())
.OrderBy(a => a.Key)
.Select(a => a.Value)
.ToArray();

How to unifiy two arrays in a dictionary?

If you have two arrays string[] a and int[] b how can you get a Dictionary<string,int> from it most efficiently and with least code possible? Assume that they contain the same number of elements.
For example, is this the best way?
Dictionary<string,int> vals = new Dictionary<string,int>();
for(int i = 0; i < size; i++)
{
vals.Add(a[i],b[i]);
}
If your goal is to match at positions within the sequences, you can use Enumerable.Zip.
int[] myInts = { 1, 2 };
string[] myStrings = { "foo", "bar"};
var dictionary = myStrings.Zip(myInts, (s, i) => new { s, i })
.ToDictionary(item => item.s, item => item.i);
And since you are working with arrays, writing it "longhand" really isn't all that long. However, you want to validate beforehand the arrays truly are equal in length.
var dictionary = new Dictionary<string, int>();
for (int index = 0; index < myInts.Length; index++)
{
dictionary.Add(myStrings[index], myInts[index]);
}
Usually, Linq can result in more expressive, easier to understand code. In this case, it's arguable the opposite is true.
If this is .Net 4, then you can do the following:
var result = a.Zip(b, (first, second) => new {first, second})
.ToDictionary(val => val.first, val => val.second);
Without Zip, you can also do this:
var result = Enumerable.Range(0, a.Length).ToDictionary(i => a[i], i => b[i]);
Using ToDictionary:
int idx = 0;
var dict = b.ToDictionary(d => a[idx++]);
var result = a.ToDictionary(x => x, x => b[a.IndexOf(x)]);

Categories