I'd like to know the best way to approach this. I have an integer array (say of 3, 4, 8, 10, 15, 24, 29, 30) and I want to sort it into 3 groups: 4 times table, 5 times table, and neither).
As the groups would suggest, it would sort the array into the 4 and 5 times table with another for items that aren't present in either.
What's the best way to approach this in C#? I'm currently using this:
int[] iArray = new int[]{3, 4, 8, 10, 15, 24, 29, 30};
var iE = iArray.GroupBy ((e) => {
if (e % 4 == 0) {
return "four";
} else if (e % 5 == 0) {
return "five";
} else {
return "other";
}
}).OrderBy (e => e.Count ());
Produces:
4
4
8
24
5
10
15
30
Other
3
29
int[] arr = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 };
If you want to get all multiples of 4 and all multiples of 5 (and have some overlap between the two) you can do this:
List<int> multiplesOf4 = (from i in arr where i % 4 == 0 select i).ToList();
List<int> multiplesOf5 = (from i in arr where i % 5 == 0 select i).ToList();
List<int> others = (from i in arr where i % 5 != 0 && i % 4 != 0 select i).ToList();
If you want no overlap, however, you need to pick which one will be dominant. I chose 4 here:
List<int> multiplesOf4 = new List<int>(),
multiplesOf5 = new List<int>(),
others = new List<int>();
foreach (int i in arr)
{
if (i % 4 == 0)
multiplesOf4.Add(i);
else if (i % 5 == 0)
multiplesOf5.Add(i);
else
others.Add(i);
}
Try this:
var numberGroupsTimes5 =
from n in numbers
group n by n % 5 into g
where g.Key == 0
select new { Remainder = g.Key, Numbers = g };
var numberGroupsTimes4 =
from n in numbers
group n by n % 4 into g
where g.Key == 0
select new { Remainder = g.Key, Numbers = g };
foreach (var g in numberGroupsTimes5)
{
string st = string.Format("Numbers with a remainder of {0} when divided by 5:" , g.Remainder);
MessageBox.Show("" + st);
foreach (var n in g.Numbers)
{
MessageBox.Show(""+n);
}
}
foreach (var g in numberGroupsTimes4)
{
string st = string.Format("Numbers with a remainder of {0} when divided by 4:", g.Remainder);
MessageBox.Show("" + st);
foreach (var n in g.Numbers)
{
MessageBox.Show("" + n);
}
}
You approach is correct. But you can do some small improvements to make it more readable and standard:
var iArray = new[] { 3, 4, 8, 10, 15, 24, 29, 30 };//Don't need to give type(int) explicitly
var iE = iArray.GroupBy(e => e % 4 == 0 ? "four" : e % 5 == 0 ? "five" : "other").OrderBy(e => e.Count());
It'll give the same results.
Related
I'm learning how to program using c#. I'm really new to this.
My question is I'm trying to create an array that shows 10 numbers. I want my code to check which numbers below 10 are divisible for 3 or 5 and sum the total.
I've tried to use the .Sum() function but says int doesn't contain a definition for Sum. I've put using System.Linq on my program.
Does anyone have an idea how to make this sum happens?
{
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sum = 1 + 2;
foreach (int n in numbers)
{
if (n % 3 == 0 || n % 5 == 0)
{
int total = n.Sum();
Console.WriteLine(total);
}
else
{
Console.WriteLine("not divisible");
}
}`
So your problem is that you are trying to call .Sum() on a variable n which is of type int (you define it here: foreach (int n in numbers), and that is not a method.
Using LINQ you could do something like:
var numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
var total = numbers.Where(n => n % 3 == 0 || n % 5 == 0).Sum();
If I understand it correct and using your code this is what you want.
int[] numbers = new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int sum = 1 + 2;
int total=0;
foreach (int n in numbers)
{
if (n % 3 == 0 || n % 5 == 0)
{
int total += n;
}
else
{
Console.WriteLine("not divisible");
}
}
Console.WriteLine(total);
I moved the printing out to after the foreach so you get one result when it is done
Everybody forgot that array should contain 10 numbers but some numbers values maybe greater than 10. Only number values below 10 should be checked. So a right answer should be
var numbers = new int[] { 1, 9, 5, 6, 8, 10,4, 15, 25, 3};
var total = numbers.Where( n => (n<10) && ( n % 3 == 0 || n % 5 == 0)).Sum();
I have an array A with values: {10, 12, 6, 14, 7} and I have an array B with values: {1, 8, 2}
I have sorted the array B in an ascending order and then combined both the arrays in a new array C as shown in the following code -
static void Main()
{
int A[] = {10, 12, 6, 14, 7};
int B[] = {1, 8, 2};
Array.Sort(B);
var myList = new List<int>();
myList.AddRange(A);
myList.AddRange(B);
int[] C = myList.ToArray();
//need values in this order: 10, 1, 12, 2, 8, 6, 14, 7
}
Now I wanna sort the array C this way: 10, 1, 12, 2, 8, 6, 14, 7
The smaller values should be between the larger values, for ex: 1 is between 10 and 12, 2 is between 12 and 8, 6 is between 8 and 14, so on and so forth.
How can I do this in C#?
If recursion is needed, how can I add it to the code?
What I understood from your example is that you are trying to alternate between large and small values such that the small value is always smaller than the number to the left and the right. I wrote an algorithm below to do that however it does not yield the exact same results you requested. However I believe it does meet the requirement.
The straggling 7 is considered the next smallest number in the sequence but there is no number that follows it. Based on your example it appears that is allowed.
To Invoke
int[] A = { 10, 12, 6, 14, 7 };
int[] B = { 1, 8, 2 };
var result = Sort(A, B);
Sort Method
public static int[] Sort(int[] A, int[] B)
{
var result = new int[A.Length + B.Length];
var resultIndex = 0;
Array.Sort(A);
Array.Sort(B);
//'Pointer' for lower index, higher index
var aLeft = 0;
var aRight = A.Length-1;
var bLeft = 0;
var bRight = B.Length - 1;
//When Items remain in both arrays
while (aRight >= aLeft && bRight >= bLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
{
if (A[aLeft] < B[bLeft])
result[resultIndex++] = A[aLeft++];
else
result[resultIndex++] = B[bLeft++];
}
//Add largest
else
{
if (A[aRight] > B[bRight])
result[resultIndex++] = A[aRight--];
else
result[resultIndex++] = B[bRight--];
}
}
//When items only in array A
while (aRight >= aLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
result[resultIndex++] = A[aLeft++];
//Add largest
else
result[resultIndex++] = A[aRight--];
}
//When items remain only in B
while (bRight >= bLeft)
{
//Add smallest
if (resultIndex % 2 > 0)
result[resultIndex++] = B[bLeft++];
//Add largest
else
result[resultIndex++] = B[bRight--];
}
return result;
}
Result
[14, 1, 12, 2, 10, 6, 8, 7]
I have a list of items (not sure they are even or odd number of items). What I wanna do is, pick up records in the pair of 5 (which actually is a list), create another list and insert these pair of 5 lists into that new list.
Thanks
I can create a group of items by doing this
MyList
.Zip(Enumerable.Range(0, MyList.Count()),
(s, r) => new {
Group = r / 5,
Item = s })
.GroupBy(i => i.Group,
g => g.Item)
.ToList();
But I want to generate a nested list.
Not sure I understand your aim correctly, but you can try to use Dictionary for it:
MyList.Zip(Enumerable.Range(0, MyList.Count()),
(s, r) => new { Group = r / 5, Item = s })
.GroupBy(i => i.Group, g => g.Item)
.ToDictionary(g => g.Key, g => g.ToList());
It looks like you want to batch elements in batches of 5 items each. The MoreLinq package already offers the Batch operator for this:
var items=Enumerable.Range(0,17);
var batches=items.Batch(5);
foreach(var batch in batches)
{
Console.WriteLine(String.Join(" - ",batch));
}
This produces :
0 - 1 - 2 - 3 - 4
5 - 6 - 7 - 8 - 9
10 - 11 - 12 - 13 - 14
15 - 16
This is far faster than grouping as it only iterates the collection once.
MoreLINQ has other operators too, like Window, WindowLeft and WindowRight that produce sliding windows of values. items.Window(5) would produce :
0 - 1 - 2 - 3 - 4
1 - 2 - 3 - 4 - 5
...
11 - 12 - 13 - 14 - 15
12 - 13 - 14 - 15 - 16
The implementation
The operator's implementation is simple enough that you can just copy it into your project:
public static IEnumerable<IEnumerable<TSource>> Batch<TSource>(this IEnumerable<TSource> source, int size)
{
return Batch(source, size, x => x);
}
public static IEnumerable<TResult> Batch<TSource, TResult>( IEnumerable<TSource> source, int size,
Func<IEnumerable<TSource>, TResult> resultSelector)
{
if (source == null) throw new ArgumentNullException(nameof(source));
if (size <= 0) throw new ArgumentOutOfRangeException(nameof(size));
if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector));
return _(); IEnumerable<TResult> _()
{
TSource[] bucket = null;
var count = 0;
foreach (var item in source)
{
if (bucket == null)
{
bucket = new TSource[size];
}
bucket[count++] = item;
// The bucket is fully buffered before it's yielded
if (count != size)
{
continue;
}
yield return resultSelector(bucket);
bucket = null;
count = 0;
}
// Return the last bucket with all remaining elements
if (bucket != null && count > 0)
{
Array.Resize(ref bucket, count);
yield return resultSelector(bucket);
}
}
}
The code uses arrays for efficiency. If you really want to use mutable lists you can change the type of bucket to a List<T>, eg :
if (bucket == null)
{
bucket = new List<TSource>(size); //IMPORTANT: set the capacity to avoid reallocations
}
bucket.Add(item);
...
Why not just GroupBy?
using System.Linq;
...
int groupSize = 5;
var result = MyList
.Select((item, index) => new {
item,
index
})
.GroupBy(pair => pair.index / groupSize,
pair => pair.item)
.Select(group => group.ToList())
.ToList();
If you have a collection of items
var items = Enumerable.Range(1, 20);
And you want to take, say, 5 at a time
var setSize = 5;
You can iterate over the collection by index, and take that 5 at a time as a list, and put all those lists of 5 into one outer list
Enumerable.Range(0, items.Count() - setSize).Select(x => items.Skip(x).Take(setSize).ToList()).ToList()
The result (from C# interactive shell) looks like
List<List<int>>(15) {
List<int>(5) { 1, 2, 3, 4, 5 },
List<int>(5) { 2, 3, 4, 5, 6 },
List<int>(5) { 3, 4, 5, 6, 7 },
List<int>(5) { 4, 5, 6, 7, 8 },
List<int>(5) { 5, 6, 7, 8, 9 },
List<int>(5) { 6, 7, 8, 9, 10 },
List<int>(5) { 7, 8, 9, 10, 11 },
List<int>(5) { 8, 9, 10, 11, 12 },
List<int>(5) { 9, 10, 11, 12, 13 },
List<int>(5) { 10, 11, 12, 13, 14 },
List<int>(5) { 11, 12, 13, 14, 15 },
List<int>(5) { 12, 13, 14, 15, 16 },
List<int>(5) { 13, 14, 15, 16, 17 },
List<int>(5) { 14, 15, 16, 17, 18 },
List<int>(5) { 15, 16, 17, 18, 19 }
}
If you want each item to only show up once in each list, you can alter the above. Let's assume there's an odd number of elements:
var items = Enumerable.Range(1, 11);
You want to change the initial range used to index into your collection. Instead of taking 5 at a time on each index, it will jump the index up by 5 each iteration. The only tricky part is making sure to handle when the collection divides the number of elements you want to take; you don't want to end up with an empty list at the end. That is, this is incorrect:
Enumerable.Range(0, items.Count() / setSize).Select( // don't do this
The statement is then
Enumerable.Range(0, ((items.Count() - 1) / setSize) + 1).Select(x => items.Skip(setSize * x).Take(setSize).ToList()).ToList();
The result (from C# interactive shell) looks like
List<List<int>>(3) {
List<int>(5) { 1, 2, 3, 4, 5 },
List<int>(5) { 6, 7, 8, 9, 10 },
List<int>(1) { 11 }
}
I have a ten element array of integers. I want to sum the elements by group, so for instance I want to add the value at element 0 with the value at element 1, then with the value at element 2, then 3, and so on through to element 9, then add the value at element 1 with the value at 2,3, through to 9 until every group of 2 values has been added together and stored in a variable. I then want to repeat the process with groups of 3, groups of 4, of 5, all the way through to group of 10. Each resultant total being stored in a separate variable. Thus far the only way I can figure out how to do it is thus :-
int i = 0;
int p = 1;
int q = 2;
int r = 3;
while (i < NumArray.Length - 3)
{
while (p < NumArray.Length - 2)
{
while (q < NumArray.Length-1)
{
while (r < NumArray.Length)
{
foursRet += NumArray[i] + NumArray[p] + NumArray[q]+ NumArray[r];
r++;
}
q++;
r = q + 1;
}
p++;
q = p + 1;
r = q + 1;
}
i++;
p = i + 1;
q = i + 2;
r = i + 3;
}
The above is an example of summing groups of 4.
I was wondering if anyone could be kind enough to show me a less verbose and more elegant way of achieving what I want. Many thanks.
Because everything is better with LINQ*:
using System; // Output is below
using System.Linq;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var inputArray = Enumerable.Range(0, 10).ToArray();
var grouped =
from Buckets in Enumerable.Range(1, inputArray.Length)
from IndexInBucket in Enumerable.Range(0, inputArray.Length / Buckets)
let StartPosInOriginalArray = IndexInBucket * Buckets
select new
{
BucketSize = Buckets,
BucketIndex = StartPosInOriginalArray,
Sum = inputArray.Skip(StartPosInOriginalArray).Take(Buckets).Sum()
};
foreach (var group in grouped)
{
Debug.Print(group.ToString());
}
Console.ReadKey();
}
}
} // SCROLL FOR OUTPUT
{ BucketSize = 1, BucketIndex = 0, Sum = 1 }
{ BucketSize = 1, BucketIndex = 1, Sum = 2 }
{ BucketSize = 1, BucketIndex = 2, Sum = 3 }
{ BucketSize = 1, BucketIndex = 3, Sum = 4 }
{ BucketSize = 1, BucketIndex = 4, Sum = 5 }
{ BucketSize = 1, BucketIndex = 5, Sum = 6 }
{ BucketSize = 1, BucketIndex = 6, Sum = 7 }
{ BucketSize = 1, BucketIndex = 7, Sum = 8 }
{ BucketSize = 1, BucketIndex = 8, Sum = 9 }
{ BucketSize = 1, BucketIndex = 9, Sum = 10 }
{ BucketSize = 2, BucketIndex = 0, Sum = 3 }
{ BucketSize = 2, BucketIndex = 2, Sum = 7 }
{ BucketSize = 2, BucketIndex = 4, Sum = 11 }
{ BucketSize = 2, BucketIndex = 6, Sum = 15 }
{ BucketSize = 2, BucketIndex = 8, Sum = 19 }
{ BucketSize = 3, BucketIndex = 0, Sum = 6 }
{ BucketSize = 3, BucketIndex = 3, Sum = 15 }
{ BucketSize = 3, BucketIndex = 6, Sum = 24 }
{ BucketSize = 4, BucketIndex = 0, Sum = 10 }
{ BucketSize = 4, BucketIndex = 4, Sum = 26 }
{ BucketSize = 5, BucketIndex = 0, Sum = 15 }
{ BucketSize = 5, BucketIndex = 5, Sum = 40 }
{ BucketSize = 6, BucketIndex = 0, Sum = 21 }
{ BucketSize = 7, BucketIndex = 0, Sum = 28 }
{ BucketSize = 8, BucketIndex = 0, Sum = 36 }
{ BucketSize = 9, BucketIndex = 0, Sum = 45 }
{ BucketSize = 10, BucketIndex = 0, Sum = 55 }
*Not everything is better with LINQ
If I understand you correctly you have an array of numbers with length n. You want to pick all combinations of m numbers from this. You then want to sum all these combinations and finally compute the sum of these sums.
For instance given n = 6 numbers you can pick m = 4 elements in 15 different ways (the numbers are indices in the array of numbers):
0 1 2 3
0 1 2 4
0 1 3 4
0 2 3 4
1 2 3 4
0 1 2 5
0 1 3 5
0 2 3 5
1 2 3 5
0 1 4 5
0 2 4 5
1 2 4 5
0 3 4 5
1 3 4 5
2 3 4 5
If n < 32 (no more than 31 numbers in your array) you can efficiently generate the indices using 32 bit arithmetic. The following function is based on Gosper's hack:
IEnumerable<UInt32> GetIndexBits(Int32 m, Int32 n) {
unchecked {
var i = (UInt32) (1 << m) - 1;
var max = (UInt32) (1 << n);;
while (i < max) {
yield return i;
var u = (UInt32) (i & -i);
var v = u + i;
i = v + (((v ^ i)/u) >> 2);
}
}
}
With m = 4 and n = 6 this function will generate these numbers (displayed in binary form):
001111
010111
011011
011101
011110
100111
101011
101101
101110
110011
110101
110110
111001
111010
111100
You can then create the sum using LINQ:
var m = 4;
var numbers = new[] { 1, 2, 3, 4, 5, 6 };
var sum = GetIndexBits(4, numbers.Length)
.Select(
bits => Enumerable
.Range(0, numbers.Length)
.Where(i => ((1 << i) & bits) != 0)
)
.Select(indices => indices.Sum(i => numbers[i]))
.Sum();
With the provided input the sum will be 210 which is the same result as foursRet in the question when NumArray contains the numbers 1 to 6.
Suppose I have this number list:
List<int> = new List<int>(){3,5,8,11,12,13,14,21}
Suppose that I want to get the closest number that is less than 11, it would be 8
Suppose that I want to get the closest number that is greater than 13 that would be 14.
The numbers in list can't be duplicated and are always ordered. How can I write Linq for this?
with Linq assuming that the list is ordered I would do it like this:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var lessThan11 = l.TakeWhile(p => p < 11).Last();
var greaterThan13 = l.SkipWhile(p => p <= 13).First();
EDIT:
As I have received negative feedback about this answer and for the sake of people that may see this answer and while it's accepted don't go further, I explored the other comments regarding BinarySearch and decided to add the second option in here (with some minor change).
This is the not sufficient way presented somewhere else:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = ~l.BinarySearch(10) -1;
var value = l[indexLessThan11];
Now the code above doesn't cope with the fact that the value 10 might actually be in the list (in which case one shouldn't invert the index)! so the good way is to do it:
var l = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
var indexLessThan11 = l.BinarySearch(10);
if (indexLessThan11 < 0) // the value 10 wasn't found
{
indexLessThan11 = ~indexLessThan11;
indexLessThan11 -= 1;
}
var value = l[indexLessThan11];
I simply want to note that:
l.BinarySearch(11) == 3
//and
l.BinarySearch(10) == -4;
Use Array.BinarySearch - no need for LINQ or visiting on average half the elements to find your target.
There are also a variety of SortedXXX classes that may be suitable for what you're doing [that will have such efficient O(log N) searches built-in]
You can do this using a binary search. If your searching for 11, well obviously you'll get the index your after. If you search for 10 and use the bitwise complement of the result, you'll get the closest match.
List<int> list = new List<int>(){3,5,8,11,12,13,14,21};
list.Sort();
int index = list.BinarySearch(10);
int found = (~index)-1;
Console.WriteLine (list[found]); // Outputs 8
The same goes searching in the other direction
int index = list.BinarySearch(15);
Console.WriteLine("Closest match : " + list[+~index]); // Outputs 21
Binary searches are also extremely fast.
closest number below 11:
int someNumber = 11;
List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };
var intermediate = from i in list
where i < someNumber
orderby i descending
select i;
var result = intermediate.FirstOrDefault();
closest number above 13:
int someNumber = 13;
List<int> list = new List<int> { 3, 5, 8, 11, 12, 13, 14, 21 };
var intermediate = from i in list
where i > someNumber
orderby i
select i;
var result = intermediate.FirstOrDefault();
This is my answer
List<int> myList = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
int n = 11;
int? smallerNumberCloseToInput = (from n1 in myList
where n1 < n
orderby n1 descending
select n1).First();
int? largerNumberCloseToInput = (from n1 in myList
where n1 > n
orderby n1 ascending
select n1).First();
var list = new List<int> {14,2,13,11,5,8,21,12,3};
var tested = 11;
var closestGreater = list.OrderBy(n => n)
.FirstOrDefault(n => tested < n); // = 12
var closestLess = list.OrderByDescending(n => n)
.FirstOrDefault(n => tested > n); // = 8
if (closestGreater == 0)
System.Diagnostics.Debug.WriteLine(
string.Format("No number greater then {0} exists in the list", tested));
if (closestLess == 0)
System.Diagnostics.Debug.WriteLine(
string.Format("No number smaler then {0} exists in the list", tested));
Here is my way hope this helps somebody!
List<float> list = new List<float> { 4.0f, 5.0f, 6.0f, 10.0f, 4.5f, 4.0f, 5.0f, 6.0f, 10.0f, 4.5f, 4.0f, 5.0f, 6.0f, 10.0f };
float num = 4.7f;
float closestAbove = list.Aggregate((x , y) => (x < num ? y : y < num ? x : (Math.Abs(x - num)) < Math.Abs(y - num) ? x : y));
float closestBelow = list.Aggregate((x , y) => (x > num ? y : y > num ? x : (Math.Abs(x - num)) < Math.Abs(y - num) ? x : y));
Console.WriteLine(closestAbove);
Console.WriteLine(closestBelow);
This means you dont have to order the list
Credit: addapted from here: How to get the closest number from a List<int> with LINQ?
The Expanded Code
float closestAboveExplained = list.Aggregate((closestAbove , next) => {
if(next < num){
return closestAbove;
}
if(closestAbove < num){
return next;
}
else{
if(Math.Abs(closestAbove - num) < Math.Abs(next - num)){
return closestAbove;
}
}
return next;
});
You can use a query for this such as:
List<int> numbers = new List<int>() { 3, 5, 8, 11, 12, 13, 14, 21 };
List<int> output = (from n in numbers
where n > 13 // or whatever
orderby n ascending //or descending
select n).ToList();