There is a string [] yield that can contain N count data. I have defined 15 count to be an example.
I want to divide these data into 6 groups.However, I cannot load the last remaining items into the array.
Where am I making a mistake?
string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
double tagLength = (int)Math.Floor(tags.Length / (double)6);
for (int i = 0; i <= tagLength-1; i++)
{
string[] groupArrays = new string[6];
Array.Copy(tags, i * 6, groupArrays, 0, 6);
}
The output i see
[0] = {1,2,3,4,5,6}
[1] = {7,8,9,10,11,12}
Should be output
[0] = {1,2,3,4,5,6}
[1] = {7,8,9,10,11,12}
[2] = {13,14,15}
I would suggest changing your code to calculate the number of groups you need to this:
int groups = (count / groupSize);
bool hasPartialGroup = count % groupSize != 0;
if (hasPartialGroup)
{
++groups;
}
The result of the first line will be integer division, so 15 / 6 will result in 2. We then see if there is a remainder using the remainder operator (%): count % groupSize. If its result isn't 0, then there is a remainder, and we have a partial group, so we have to account for that.
So for groups = 15 and groupSize = 6, we'll get count = 3. For groups = 12 and groupSize = 6, we'll get count = 2, etc.
Fixing your code to use this, it might look like:
string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
int count = tags.Length;
const int groupSize = 6;
int groups = (count / groupSize);
bool hasPartialGroup = count % groupSize != 0;
if (hasPartialGroup)
{
++groups;
}
for (int i = 0; i < groups; i++)
{
// you can't copy beyond the end of the array so we have to choose between the remaining ungrouped items and the group size
int currentGroupSize = Math.Min(tags.Length - i*groupSize, groupSize);
// I'm assuming for a partial group you only want this to be as big as the number of items.
// If you want it to always be 6 then change new string[currentGroupSize] to new string[groupSize] and you should be OK.
string[] groupArrays = new string[currentGroupSize];
Array.Copy(tags, i * groupSize, groupArrays, 0, currentGroupSize);
Console.WriteLine(string.Join(",", groupArrays));
}
Try it online // Example with fixed group size
Alternatively, you could create a batching helper method:
private static IEnumerable<T[]> BatchItems<T>(IEnumerable<T> source, int batchSize)
{
var collection = new List<T>(batchSize);
foreach (var item in source)
{
collection.Add(item);
if (collection.Count == batchSize)
{
yield return collection.ToArray();
collection.Clear();
}
}
if (collection.Count > 0)
{
yield return collection.ToArray();
}
}
This will collect batchSize number items together and then return one group at a time. You can read about how this works with yield return here.
Usage:
string[] tags = {"1","2","3","4","5","6","7","8","9","10","11","12","13","14","15"};
List<string[]> batchedTags = BatchItems(tags, 6).ToList();
This will result in 3 string arrays, containing 1,2,3,4,5,6, 7,8,9,10,11,12, and 13,14,15.
You could also make this into an extension method.
Try it online
If you mean why you are not getting groups of 6, the reason for this is that you are flooring the length of tags / 6. So, if the last group has the length of less that 6, it won't get added. Add this to the end:
if (tags.Length%6!=0) { string[] groupArrays = tags[i..tags.Length] } // You can do this manually.
As said before, it's because you use Math.Floor(). Use either Math.Ceiling or remove the -1 from i<= taglength - 1.
Array.Copy will still produce errors when you're tags aren't an exact multiple of 6.
Below code should do the trick and won't produce an error
string[] tags = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" };
int baselength = 6;
double tagLength = (int)Math.Floor(tags.Length / (double)6);
int length = baselength;
for (int i = 0; i <= tagLength; i++)
{
string[] groupArrays = new string[baselength];
if (i == tagLength)
length = ((i + 1) * length) - tags.Length;
if(length > 0 && length < baselength)
Array.Copy(tags, i * 6, groupArrays, 0, length);
}
Because you use Math.Floor(...). You should use Math.Ceiling(...) instead.
(int)Math.Floor(15d / 6d) // returns 2 >> 2 groups.
(int)Math.Ceiling(15d / 6d) // returns 3 >> 3 groups.
Beware though, you will get an ArgumentOutOfRangeException in Array.Copy, since index 3 * 6 does not exist. You will have to find a way around that.
One possible solution:
string[] tags = { "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" };
double tagLength = (int)Math.Ceiling(tags.Length / (double)6);
for (int i = 0; i <= tagLength - 1; i++)
{
int arrLength = (i + 1) * 6 <= tags.Length ? 6 : tags.Length % 6;
string[] groupArrays = new string[arrLength]; // or six if you always want a length of 6
Array.Copy(tags, i * 6, groupArrays, 0, arrLength);
}
Or using Linq:
for (int i = 0; i < (int)Math.Ceiling(tags.Length / 6d); i++)
{
string[] groupArrays = tags.Skip(i * 6).Take(6).ToArray();
}
Related
I have 11 letters and they have values. The first have the same value as their numbering 1 to 10, but the eleventh has a value of 20. The question is how can I print out all 3 letter combinations with a total value of 23. Can you please help me I don’t even know where to start?
Let's first put your letters into a Dictionary<string, int> where Key is the letter, and Value is the value associated with each key.
var values = new Dictionary<string, int>
{
{ "A", 1 },
{ "B", 2 },
{ "C", 3 },
{ "D", 4 },
{ "E", 5 },
{ "F", 6 },
{ "G", 7 },
{ "H", 8 },
{ "I", 9 },
{ "J", 10 },
{ "K", 20 }
};
To get all 3 letter combos whose values add up to 23, first you need to get all 3 letter combos. So let's do that. The following function iterates through the dictionary and gets all 3 letter combos.
private static List<List<KeyValuePair<string, int>>> GetAll3LetterCombos(Dictionary<string, int> values)
{
var comboList = new List<List<KeyValuePair<string, int>>>();
for (int outer = 0; outer < values.Count; outer++)
{
for (int mid = outer + 1; mid < values.Count; mid++)
{
for (int inner = mid + 1; inner < values.Count; inner++)
{
var combo = new List<KeyValuePair<string, int>>
{
values.ElementAt(outer),
values.ElementAt(mid),
values.ElementAt(inner)
};
comboList.Add(combo);
}
}
}
return comboList;
}
Then, using LINQ, we can filter out that result where the sum of values in each KeyValuePair is equal to 23.
var threeLetterCombos = GetAll3LetterCombos(values);
var addsTo23 = threeLetterCombos.Where(x => x.Sum(y => y.Value) == 23).ToList();
The result:
[A 1] [B 2] [K 20]
[D 4] [I 9] [J 10]
[E 5] [H 8] [J 10]
[F 6] [G 7] [J 10]
[F 6] [H 8] [I 9]
One way to do this is a brute-force solution, where you compare every possible combination of three-letter values and store those that equal 23.
First, a simple class to represent a Letter, that has a Text property and a Value property:
public class Letter
{
public int Value { get; set; }
public char Text { get; set; }
public override string ToString()
{
return $"{Text} ({Value})";
}
}
Then, we can populate a list of these from A-K, where each letter has it's corresponding "index + 1" value except the last, which is 20:
var letters = Enumerable.Range(65, 10)
.Select(i => new Letter {Value = i - 64, Text = (char)i })
.ToList();
letters.Add(new Letter {Value = 20, Text = 'K'});
Then we can create a List<List<Letter>> object to hold the combinations that add up to 23:
var combos = new List<List<Letter>>();
And the brute-force solution is to simply use 3 loops to add a List<Letter> of the sum of each number with every combination of two numbers after it:
for (int first = 0; first < letters.Count; first++)
{
for (int second = first + 1; second < letters.Count; second++)
{
for (int third = second + 1; third < letters.Count; third++)
{
combos.Add(new List<Letter>
{letters[first], letters[second], letters[third]});
}
}
}
When this is done, we can filter and display the results of only those whose sum is 23:
// Output the combinations
Console.WriteLine("Here are the combinations that equal 23:\r\n");
foreach (var combo in combos.Where(c => c.Sum(l => l.Value) == 23))
{
Console.WriteLine(string.Join(" +\t", combo) +
$"\t= {combo.Sum(l => l.Value)}");
}
Output
Here is the code that outputs 1 or 0 depending on the equality of the 2 arrays
static void Main(string[] args)
{
while (true)
{
Console.WriteLine(Here());
}
Here is where the magic happens.
static int Here()
{
Random rnd = new Random();
PlayerInput();
int[] intarray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
string[] sarray = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
int i = rnd.Next(10); // creates a number between 1 and 10
int x = rnd.Next(10);
string iarray = intarray[x].ToString();
if (iarray == sarray[i])
{
return 1;
}
else
{
return 0;
}
}
it outputs 0 when the two arrays don't equal and 1 vise versa. now I want to count the amount of times it outputs 0 & 1.
Questions:
How could I do that?
Should I transfer the output to an array for easier manipulation?
Unless I'm misunderstanding your question, it seems like you could simply have two counter variables:
static void Main(string[] args)
{
int totalOnes = 0;
int totalZeroes = 0;
while (true) // need to replace this with something that will actually exit!!
{
int ret = Here();
if (ret == 1) totalOnes++; else totalZeroes++;
Console.WriteLine(ret);
}
Console.WriteLine("Total Ones: {0} Total Zeroes: {1}", totalOnes, totalZeroes);
}
EDIT: Thanks to L J for pointing out that your while loop will never exit since you have while (true). You need to address that.
like this
static void Main(string[] args)
{
var zeroCount = 0;
var oneCount = 0;
while (true)
{
var result = Here();
if (result == 1) oneCount++;
if (result == 0) zeroCount++;
Console.WriteLine($"Actual result {result}, zero count {zeroCount}, One count {oneCount}");
}
}
static int Here()
{
Random rnd = new Random();
PlayerInput();
int[] intarray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
string[] sarray = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
**var Count1 = 0;
var Count0 = 0;**
int i = rnd.Next(10); // creates a number between 1 and 10
int x = rnd.Next(10);
string iarray = intarray[x].ToString();
if (iarray == sarray[i])
{
**Count1++;**
return 1;
}
else
{
**Count0++;**
return 0;
}
}
Count0 will contain the number of times 0 was outputted.
Count1 will contain the number of times 1 was outputted.
I have an Array of bytes, representing the RGB values of an image.
How could I group each offset of 3 values (RGB) of this array to apply my tweaks (like removing the repeated colors), maybe using Linq?
["120", "100", "10", "120", "100", "10", "10", "60", "110"]
to
["120", "100", "10", "10", "60", "110"]
You can use Select to add index to your enumeration and later group by index / 3. A bit of post-processing on each of the groups and you should be able to get what you want:
var grouped = source.Select((x,i) => new { x, i })
.GroupBy(x -> x.i / 3)
.Select(g => g.ToList())
.Select(g => new { R = g[0], G = g[1], B = g[2] })
.Distinct();
But that feels quite ugly. If I were you I'd probably write a simple custom LINQ method (an extension method on IEnumerable<int>) to do this more efficiently.
Shorter version that gets the distinct RGB values and their indexes:
string[] a = { "120", "100", "10", "120", "100", "10", "10", "60", "110" };
var l = Enumerable.Range(0, a.Length / 3)
.ToLookup(i => new { R = a[i * 3], G = a[i * 3 + 1], B = a[i * 3 + 2] });
If you don't mind using a loop instead of Linq:
class Program
{
static void Main(string[] args)
{
byte[] array = new byte[] { 120, 100, 10, 120, 100, 10, 10, 60, 110 };
List<byte[]> grouped = new List<byte[]>();
// This loop will populate the list grouped with arrays of 3 bytes each, each representing an value for RGB
for(int i = 0; i + 2 < array.Length; i += 3)
{
byte[] currentColor = new byte[]
{
array[i],
array[i + 1],
array[i + 2]
};
grouped.Add(currentColor);
}
// Here you will remove repeated elements for RGB
// Notice you will have to create the ByteArrayComparer class, you will find the code right under this one
var noRepeatedElements = grouped.Distinct<byte[]>(new ByteArrayComparer());
// Print the non repeated elements for testing purposes
foreach(var rgb in noRepeatedElements)
{
foreach(var value in rgb)
{
Console.Write($"\"{value}\"");
}
}
Console.ReadKey();
}
}
Where ByteArrayComparer is the following class
// This class will compare two distinct byte arrays and check if their elements are the same
public class ByteArrayComparer : IEqualityComparer<byte[]>
{
public bool Equals(byte[] x, byte[] y)
{
int smallerArrayLength = Math.Min(x.Length, y.Length);
bool elementsWithSameValue = true;
for(int i = 0; i < smallerArrayLength; i++)
{
// If there is a single element which is different, we know the arrays are different and can break the loop.
if(x[i] != y[i])
{
elementsWithSameValue = false;
break;
}
}
return elementsWithSameValue;
}
public int GetHashCode(byte[] obj)
{
int hash = 0;
for(int i = 0; i < obj.Length; i++)
{
hash += obj[i].GetHashCode();
}
return hash;
}
}
Note that grouped now is a List of arrays of bytes. Each element in grouped has three elements, representing a single RGB value.
Now you can work with the rgb values as you please.
Using Microsoft's Reactive Framework Team's Interactive Extensions (NuGet "Ix-Main") you can do this:
byte[] array = new byte[]
{
120, 100, 10, 120, 100, 10, 10, 60, 110
};
byte[] results =
array
.Buffer(3)
.Distinct(xs => String.Join(",", xs))
.SelectMany(x => x)
.ToArray();
That will give you { 120, 100, 10, 10, 60, 110 }.
So what's a good, simple algorithm to create a loop in C# where every time a certain value appears in an array it adds 1 to a counter in another array?
For example I have this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication22
{
class Program
{
const int SIZE = 12;
static void Main(string[] args)
{
int[] numbers = new int[SIZE] {5, 5, 5, 7, 7, 7, 9, 7, 9, 9, 9, 1};
string[] letters = new string[SIZE] { "m", "m", "s", "m", "s", "s", "s", "m", "s", "s", "s", "s" };
int[] values = new int[SIZE] {15, 22, 67, 45, 12, 21, 24, 51, 90, 60, 50, 44};
string[] status = new string[SIZE] { "f", "m", "f", "a", "m", "f", "f", "f", "m", "f", "m", "f" };
int[] Count = new int[4];
int x = 0;
int i = 0;
for (i = 0; i < SIZE - 1; i++)
{
if (numbers[i] > 0 && numbers[i] < SIZE)
{
x = Count[i];
Count[x]++;
}
}
for (i = 0; i < 4; i++)
{
Console.WriteLine("{0}", Count[4]);
}
}
}
}
I am only counting the number of times 4 numbers appear in the numbers array. Someone suggested I use the method in the first loop but it doesn't seem to be working and creates an error that the index is out of bounds in the array. I want to display the number of times each of those numbers(5, 7,9 and 1) appear in 4 rows.
EDIT: Without using LINQ or any other fancy thing like Dictionary or whatever.
You're getting an index out of bounds error because of this section:
for (i = 0; i < SIZE - 1; i++)
{
if (numbers[i] > 0 && numbers[i] < SIZE)
{
x = Count[i];
Notice that you're iterating through 0 to SIZE - 1 (11) when Count only has a size of 4.
You can do this task pretty easily with LINQ though.
int[] numbers = new int[SIZE] { 5, 5, 5, 7, 7, 7, 9, 7, 9, 9, 9, 1 };
var count = numbers
.GroupBy(e => e)
.Where(e => e.Count() == 4)
.Select(e => e.First());
So it groups the numbers by their value, we then refine the list to only include groups of 4, then select the first of each to be left with a collection of ints.
Here is a non-LINQ based solution using a Dictionary to store the count of numbers.
int[] numbers = new int[SIZE] { 5, 5, 5, 7, 7, 7, 9, 7, 9, 9, 9, 1 };
var dictionary = new Dictionary<int, int>();
var numbersWithFour = new List<int>();
foreach (var number in numbers)
{
if (dictionary.ContainsKey(number))
dictionary[number]++;
else
dictionary.Add(number, 1);
}
foreach (var val in dictionary)
{
if (val.Value == 4)
{
numbersWithFour.Add(val.Key);
}
}
With a little modification to your program you can get some results.
int[] numbers = new int[SIZE] { 5, 5, 5, 7, 7, 7, 9, 7, 9, 9, 9, 1 };
string[] letters = new string[SIZE] { "m", "m", "s", "m", "s", "s", "s", "m", "s", "s", "s", "s" };
int[] values = new int[SIZE] { 15, 22, 67, 45, 12, 21, 24, 51, 90, 60, 50, 44 };
string[] status = new string[SIZE] { "f", "m", "f", "a", "m", "f", "f", "f", "m", "f", "m", "f" };
// Set the size of Count to maximum value in numbers + 1
int[] Count = new int[9 + 1];
int x = 0;
int i = 0;
for (i = 0; i < SIZE - 1; i++)
{
if (numbers[i] > 0 && numbers[i] < SIZE)
{
// Use value from numbers as the index for Count and increment the count
Count[numbers[i]]++;
}
}
for (i = 0; i < Count.Length; i++)
{
// Check all values in Count, printing the ones where the count is 4
if (Count[i] == 4)
Console.WriteLine("{0}", i);
}
Output:
7
9
Use LINQ to do the work
using System.Linq;
var numQuery =
from num in numbers
where num == 5
select num;
Console.WriteLine("Count of 5: " + numQuery.Count);
Or use the method syntax
var numQuery = numbers.Where(num => num == 5);
Console.WriteLine("Count of 5: " + numQuery.Count);
See here for the overview and here for query vs method-syntax.
Found a sample for GroupBy, look here.
I used Regex for my solution since I only had three values.
String results = "" + one.ToString() + " " + two.ToString() + " " + three.ToString();
int count1 = Regex.Matches(results, #one.ToString()).Count;
int count2 = Regex.Matches(results, #two.ToString()).Count;
int count3 = Regex.Matches(results, #three.ToString()).Count;
Seems 'hacky', but worked for me. It'll work with strings or numbers but only if you're working with a few values. Pretty efficient in that case. If not, I think the other answer would be a better option.
your count array has 4 fields ...
one with the index 0, 1, 2 and 3
so what will happen if a number like 4 (or greater) happens to be counted? yor code tries to access index 4 ... which does not exist ...
This is the naive Solution for finding " Counting the number of times a value appears in an array "
Idea : Build a Hash map in Array
Solution :
using System.Collections.Generic;
using System.Text;
namespace GetArrEleFrequency
{
class Program
{
static int[] Arr = new int[5] { 3, 3, 0, 2, 0 };
static int[] Key = new int[5];
static int[] value = new int[5];
static void Main(string[] args)
{
int keyItr = -1, ValueItr = -1, tempIndex = 0, tempValue = 0;
for (int i=0; i <= Arr.Length-1;i++) {
if (!(isPresent(Arr[i]))) {
keyItr += 1;ValueItr += 1;
Key[keyItr] = Arr[i];
value[ValueItr] = 1;
} else {
value[tempIndex] = value[getIndex(Arr[i])] + 1;
}
}
for (int i=0;i<=Key.Length-1;i++) {
Console.WriteLine(Key[i] + "-" + value[i]);
}
Console.ReadKey();
}
public static Boolean isPresent(int num) {
Boolean temp = false;
for (int i=0; i <= Key.Length-1;i++) {
if (Key[i] == num) {
temp = true;
break;
} else {
temp = false;
}
}
return temp;
}
public static int getIndex(int num) {
int temp = 0;
for (int i=0;i<=Key.Length-1;i++) {
if (Key[i] == num) {
break;
} else {
temp += 1;
}
}
return temp;
}
}
}
Output :
3 - 2
0 - 2
2 - 1
0 - 0
0 - 0
static void Main(string[] args)
{
int[] arr = new int[] { 45, 34, 23, 67, 10, 99,99,10 };
foreach(int i in arr.Distinct())
{
int count = occurance(arr,i);
Console.WriteLine(i + "-Occurred For :" + count);
}
Console.ReadLine();
}
public static int occurance(int[] arr,int x)
{
int count = 0;
foreach(int num in arr)
{
if(x==num)
{
count++;
}
}
return count;
}
}
I think the question hasn't been answered without using lists, LINQ or Dictionary so here is my suggestion:
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
class Program
{
static void Main()
{
int n = int.Parse(Console.ReadLine()); // the size of the array
int[] ints = new int[n]; //an array to store the items, integers in this case
int[] freq = new int[n]; //an array to store the frequency of each element with the same index
for (int i = 0; i < n; i++) // a loop that takes each element on a new row
{
ints[i] = int.Parse(Console.ReadLine());
}
for (int j = 0; j < n; j++) // loops to iterate through the ints array and pick up the
// frequencies and store them in the freq array
{
for (int k = 0; k < n; k++)
{
if (ints[j] == ints[k] && k != n)
{
freq[j]++;
}
}
}
int indexAtMax = freq.ToList().IndexOf(freq.Max()); //this picks up the index of the first maximum count
int mostFrequentNumber = ints[indexAtMax]; // the actual number behind the same inex in the ints array
int frequencyOfRepeating = freq[indexAtMax]; // the actual number of the frequency
Console.WriteLine($"The most frequent number is:{mostFrequentNumber} and it repeats {frequencyOfRepeating} times)");
}
}
I have a dynamic number of items to divide into a maximum of 4 columns, with the proper html format surrounding then, lets say:
string[] s = { "1", "2", "3", "4", "5", "6", "7", "8", "9" }; // from 1 to n itens
To format into this html:
<ul>
<li>
1
2
3
</li>
<li>
4
5
</li>
<li>
6
7
</li>
<li>
8
9
</li>
</ul>
Edit: my website problem:
If you have words as itens, putting the itens this way will organize the words into alphabetically columns (people read this way), not alphabetically rows. Like:
a d g i
b e h j
c f
Instead of:
a b c d
e f g h
i j
Assuming that you want to evenly distribute any remainders, this will do the job:
string[] s = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
// create the 4 buckets with equal distribution
var buckets = Enumerable.Repeat(s.Length / 4, 4).ToArray();
// distribute any remainders evenly starting from the first bucket
var rem = s.Length % 4;
for (var i = 0; i < rem; i++) buckets[i]++;
var idx = 0;
Console.WriteLine("<ul>");
foreach (var bucket in buckets)
{
Console.WriteLine("\t<li>");
foreach (var _ in Enumerable.Range(1, bucket))
{
Console.WriteLine("\t\t{0}", s[idx++]);
}
Console.WriteLine("\t</li>");
}
Console.WriteLine("</ul>");
For the above code, here is what some edge cases return.
{} = 4 empty items in list
{ "1", "2", "3"} = 1, 2, 3 in the first three items, fourth item empty
{ "1", "2", "3", "4", "5"} = 1, 2 in the first item, 3, 4, 5 in the other items
Just loop over the array distributing the array items with a few if statements within it.
int j = 0;
for (int i = 0; i < s.Length; i++)
{
if (j == 0)
// put s[i] in column 1 j = j +1
else if (j == 1)
// put s[i] in column 2 j = j +1
else if (j == 2)
// put s[i] in column 3 j = j +1
if (j == 3)
// put s[i] in column 4 set j = 0
}
Since you want to group by columns instead of rows, just realize that you're ultimately going to have to do SOMETHING with the index. The easiest way to do this is to transform the items into Item/Index pairs and group by those indexes somehow.
s.Select((tr, ti) => new { Index = ti, Item = tr })
.GroupBy(tr => tr.Index % SOME_MAGIC_NUMBER)
If you want to instead group by rows, change the % operator to a division / and you'll be set. This will now take all your items and group them into the however many items you specify (based on either row or column). To transform them, all you have to do is another select:
.Select(tr => "<li>" + string.Join(" ", tr.Select(tstr => tstr.Item.ToString()).ToArray()) + "</li>")
This will get you a list of all your list items in whatever format you want. If you want to include <br /> between the elements of each <li> then just change the first argument of the string.Join call.