How to find repetitions/duplicates in the array within 10 elements apart - c#

I have an array like following:
{1,5,5,4,5,6,7,8,9,10,11,12,13,14,1,16,17,5}
I want to find duplicates within each 10 elements from one to another.
I need a code that can tell me that 5 was duplicated 3 times within 10 elements (there are at most only 1 element between 5s (4). It should igore last 5 as it is too far away. Only three 5s are within 10 elements).
I don't want code to return 1, because there are 13 element in between both 1s.
I have a code that can count duplicates but how to change it so it can count duplicates withing 10 elements?
var dict = new Dictionary<string, int>();
foreach (var count in combined2)
{
if (dict.ContainsKey(count))
dict[count]++;
else
dict[count] = 1;
}
foreach (var val in dict)
{
MessageBox.Show(val.Key + " occurred " + val.Value + " times");
}
I'm only concerned with duplicates that occur the most. If some number get duplicated twice but another gets duplicated 3 times. I would only like to know about number that got duplicated 3 times (withing 10 items). Thank you

Make a dictionary max defaulting to 0
Make a dictionary seen defaulting to 0
Count count from 0 up to N, where N is number of elements.
after N >= 10, decrement seen[array[count - 10]]
Increment seen[array[count]]
If that number is higher than max[array[count]], update it
Repeat
Return the key of the highest value in max.
This way, seen always has the accurate count in the 10-element window, and max will have the maximum number of appearances of each element in a 10-element window.

This code finds the first item with the higher number of occurrences inside the "numbers" array (within n = 10 elements):
int n = 10;
int[] numbers = new int[] {1,5,5,4,5,6,7,8,9,10,11,12,13,14,1,16,17,5};
int mostDuplicatedNumber = 0, numberOfMaxOccurrences = 0;
for(int count = 0; count < numbers.Length - n; count++)
{
var groupOfNumbers = numbers.Skip(count).Take(n).GroupBy(i => i).OrderByDescending(i => i.Count());
if(numberOfMaxOccurrences < groupOfNumbers.First().Count())
{
numberOfMaxOccurrences = groupOfNumbers.First().Count();
mostDuplicatedNumber = groupOfNumbers.First().Key;
}
}
Console.WriteLine("Most duplicated number is " + mostDuplicatedNumber + " with " + numberOfMaxOccurrences + " occurrences");

Try out this way. I have not tested using IDE just wrote while travelling. Let me know if you encounter any error. What it does simply take first 10 elements and finds number of occurrence i.e. repetition but then ( you would like to display most repeated number in that case you have to hold those repeated numbers in another array and swap the elements to get most repeated and least repeated one as you asking in your question I have not implemented this part ) .
.................
int[] inputArray= {1,5,5,4,5,6,7,8,9,10,11,12,13,14,1,16,17,5} // total input elements
int[] mostAndLeastOccuranceArray=new int[10] ;
int skip=0;
int limit=10;
int[] resultArray=new int[10];
for (int i = skip; i < inputArray.Length; i++)
{
if(i<limit)
{
resultArray[i]=inputArray[i];
skip=skip+1;
}else
{
findOccurance(resultArray); // call in every 10 elements array subset
resultArray=new int[10]; // re-initialize the array
limit=limit+10; // increase the limit for next iteration remember loop has not finished yet
}
}
public void findOccurance(int[] resultArray)
{
var dict = new Dictionary < int,int > ();
foreach(var value in resultArray)
{
if (dict.ContainsKey(value)) dict[value]++;
else dict[value] = 1;
}
foreach(var pair in dict)
{
mostAndLeastOccuranceArray[pair.Key]=pair.Value; // store the repeated value
Console.WriteLine("Value {0} occurred {1} times", pair.Key, pair.Value);
}
// call the method to find most and least occurance elements within each array subsets
findMostAndLeastOccuranceElements(mostAndLeastOccuranceArray)
// re-initialize
mostAndLeastOccuranceArray=new int[10] ;
}
public void findMostAndLeastOccuranceElements(int[] mostAndLeastOccuranceArray)
{
// now find most and least repeated elements within each 10 elements block
}

A simpler solution would be to use LINQ. Here I wrote a simple method to count the number of time a value is repeated.
public int CountRepetitions(List<int> myLists,int maxValues,int number)
{
if (myLists.Count > maxValues)
return myLists.Take(maxValues).Count(v => v == number);
else return 0;
}

Related

Split a list into n equal parts

Given a sorted list, and a variable n, I want to break up the list into n parts. With n = 3, I expect three lists, with the last one taking on the overflow.
I expect: 0,1,2,3,4,5, 6,7,8,9,10,11, 12,13,14,15,16,17
If the number of items in the list is not divisible by n, then just put the overflow (mod n) in the last list.
This doesn't work:
static class Program
{
static void Main(string[] args)
{
var input = new List<double>();
for (int k = 0; k < 18; ++k)
{
input.Add(k);
}
var result = input.Split(3);
foreach (var resul in result)
{
foreach (var res in resul)
{
Console.WriteLine(res);
}
}
}
}
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
int i = 0;
var splits = from item in list
group item by i++ % parts into part
select part.AsEnumerable();
return splits;
}
}
I think you would benefit from Linq's .Chunk() method.
If you first calculate how many parts will contain the equal item count, you can chunk list and yield return each chunk, before yield returning the remaining part of list (if list is not divisible by n).
As pointed out by Enigmativity, list should be materialized as an ICollection<T> to avoid possible multiple enumeration. The materialization can be obtained by trying to cast list to an ICollection<T>, and falling back to calling list.ToList() if that is unsuccessful.
A possible implementation of your extension method is hence:
public static IEnumerable<IEnumerable<T>> Split<T>(this IEnumerable<T> list, int parts)
{
var collection = list is ICollection<T> c
? c
: list.ToList();
var itemCount = collection.Count;
// return all items if source list is too short to split up
if (itemCount < parts)
{
yield return collection;
yield break;
}
var itemsInEachChunk = itemCount / parts;
var chunks = itemCount % parts == 0
? parts
: parts - 1;
var itemsToChunk = chunks * itemsInEachChunk;
foreach (var chunk in collection.Take(itemsToChunk).Chunk(itemsInEachChunk))
{
yield return chunk;
}
if (itemsToChunk < itemCount)
{
yield return collection.Skip(itemsToChunk);
}
}
Example fiddle here.
I see two issues with your code. First, the way you're outputting the results, it's impossible to tell the groupings of the values since you're just outputing each one on its own line.
This could be resolved buy using Console.Write for each value in a group, and then adding a Console.WriteLine() when the group is done. This way the values from each group are displayed on a separate line. We also might want to pad the values so they line up nicely by getting the length of the largest value and passing that to the PadRight method:
static void Main(string[] args)
{
var numItems = 18;
var splitBy = 3;
var input = Enumerable.Range(0, numItems).ToList();
var results = input.Split(splitBy);
// Get the length of the largest value to use for padding smaller values,
// so all the columns will line up when we display the results
var padValue = input.Max().ToString().Length + 1;
foreach (var group in results)
{
foreach (var item in group)
{
Console.Write($"{item}".PadRight(padValue));
}
Console.WriteLine();
}
Console.Write("\n\nDone. Press any key to exit...");
Console.ReadKey();
}
Now your results look pretty good, except we can see that the numbers are not grouped as we expect:
0 3 6 9 12 15
1 4 7 10 13 16
2 5 8 11 14 17
The reason for this is that we're grouping by the remainder of each item divided by the number of parts. So, the first group contains all numbers whose remainder after being divided by 3 is 0, the second is all items whose remainder is 1, etc.
To resolve this, we should instead divide the index of the item by the number of items in a row (the number of columns).
In other words, 18 items divided by 3 rows will result in 6 items per row. With integer division, all the indexes from 0 to 5 will have a remainder of 0 when divided by 6, all the indexes from 6 to 11 will have a remainder of 1 when divided by 6, and all the indexes from 12 to 17 will have a remainder of 2 when divided by 6.
However, we also have to be able to handle the overflow numbers. One way to do this is to check if the index is greater than or equal to rows * columns (i.e. it would end up on a new row instead of on the last row). If this is true, then we set it to the last row.
I'm not great at linq so there may be a better way to write this, but we can modify our extension method like so:
public static IEnumerable<IEnumerable<T>> Split<T>(
this IEnumerable<T> list, int parts)
{
int numItems = list.Count();
int columns = numItems / parts;
int overflow = numItems % parts;
int index = 0;
return from item in list
group item by
index++ >= (parts * columns) ? parts - 1 : (index - 1) / columns
into part
select part.AsEnumerable();
}
And now our results look better:
// For 18 items split into 3
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
// For 25 items split into 7
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
15 16 17
18 19 20 21 22 23 24
This should work.
So each list should (ideally) have x/n elements,
where x=> No. of elements in the list &
n=> No. of lists it has to be split into
If x isn't divisible by n, then each list should have x/n (rounded down to the nearest integer). Let that no. be 'y'. While the last list should have x - y*(n - 1). Let that no. be 'z'.
What the first for-loop does is it repeats the process of creating a list with the appropriate no. of elements n times.
The if-else block is there to see if the list getting created is the last one or not. If it's the last one, it has z items. If not, it has y items.
The nested for-loops add the list items into "sub-lists" (List) which will then be added to the main list (List<List>) that is to be returned.
This solution is (noticeably) different from your signature and the other solutions offered. I used this approach because the code is (arguably) easier to understand albeit longer. When I used to look for solutions, I used to apply solutions where I could understand exactly what was going on. I wasn't able to fully understand the other solutions to this question (yet to get a proper hang of programming) so I presented the one I wrote below in case you were to end up in the same predicament.
Let me know if I should make any changes.
static class Program
{
static void Main(string[] args)
{
var input = new List<String>();
for (int k = 0; k < 18; ++k)
{
input.Add(k.ToString());
}
var result = SplitList(input, 5);//I've used 5 but it can be any number
foreach (var resul in result)
{
foreach (var res in result)
{
Console.WriteLine(res);
}
}
}
public static List<List<string>> SplitList (List<string> origList, int n)
{//"n" is the number of parts you want to split your list into
int splitLength = origList.Count / n; //splitLength is no. of items in each list bar the last one. (In case of overflow)
List<List<string>> listCollection = new List<List<string>>();
for ( int i = 0; i < n; i++ )
{
List<string> tempStrList = new List<string>();
if ( i < n - 1 )
{
for ( int j = i * splitLength; j < (i + 1) * splitLength; j++ )
{
tempStrList.Add(origList[j]);
}
}
else
{
for ( int j = i * splitLength; j < origList.Count; j++ )
{
tempStrList.Add(origList[j]);
}
}
listCollection.Add(tempStrList);
}
return listCollection;
}
}

Variable number of for loops without recursion but with Stack?

I know the usual approach for "variable number of for loops" is said to use a recursive method. But I wonder if I could solve that without recursion and instead with using Stack, since you can bypass recursion with the use of a stack.
My example:
I have a variable number of collections and I need to combine every item of every collection with every other item of the other collections.
// example for collections A, B and C:
A (4 items) + B (8 items) + C (10 items)
4 * 8 * 10 = 320 combinations
I need to run through all those 320 combinations. Yet at compile time I don't know if B or C or D exist. How would a solution with no recursive method but with the use of an instance of Stack look like?
Edit:
I realized Stack is not necessary here at all, while you can avoid recursion with a simple int array and a few while loops. Thanks for help and info.
Not with a stack but without recursion.
void Main()
{
var l = new List<List<int>>()
{
new List<int>(){ 1,2,3 },
new List<int>(){ 4,5,6 },
new List<int>(){ 7,8,9 }
};
var result = CartesianProduct(l);
}
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct = new[] { Enumerable.Empty<T>()};
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] {item})
);
}
Function taken form Computing a Cartesian Product with LINQ
Here is an example of how to do this. Algorithm is taken from this question - https://stackoverflow.com/a/2419399/5311735 and converted to C#. Note that it can be made more efficient, but I converted inefficient version to C# because it's better illustrates the concept (you can see more efficient version in the linked question):
static IEnumerable<T[]> CartesianProduct<T>(IList<IList<T>> collections) {
// this contains the indexes of elements from each collection to combine next
var indexes = new int[collections.Count];
bool done = false;
while (!done) {
// initialize array for next combination
var nextProduct = new T[collections.Count];
// fill it
for (int i = 0; i < collections.Count; i++) {
var collection = collections[i];
nextProduct[i] = collection[indexes[i]];
}
yield return nextProduct;
// now we need to calculate indexes for the next combination
// for that, increase last index by one, until it becomes equal to the length of last collection
// then increase second last index by one until it becomes equal to the length of second last collection
// and so on - basically the same how you would do with regular numbers - 09 + 1 = 10, 099 + 1 = 100 and so on.
var j = collections.Count - 1;
while (true) {
indexes[j]++;
if (indexes[j] < collections[j].Count) {
break;
}
indexes[j] = 0;
j--;
if (j < 0) {
done = true;
break;
}
}
}
}

Output a reserve random list (list function) in C#

I use List function in C# and make it random parameter. This is my code. If it output a list like this: 15 20 10 3 6
How can I output again with the reseve of list above like: 6 3 10 20 15
List<int> dso = new List<int>(20);
Random a = new Random();
for (int i = 0; i < dso.Capacity; i++)
{
int k = a.Next(100);
dso.Add(k);
Console.Write("{0} ", k);
}
for(int i=dso.Capacity;i<20;i--)
{
Console.Write("{0} ", dso[i]);
}
If you're just trying to reverse the list order then use Reverse() like this:
dso.Reverse();
foreach (var number in dso)
{
Console.Write(number + " ");
}
As you appear to be simply writing out the list in full once it's reversed you can use a foreach loop. If however you need more control of where you start in the list or jump around in the list then a for loop is better.
If you want for loop, it should be
for (int i = dso.Count - 1; i >= 0; i--) {
Console.Write("{0} ", dso[i]);
}
Comments:
Count is the number of actual list items; Capacity is reserved memory
List<T> is zero based that's why dso.Count - 1
since you loop in reversed order, condition is i >= 0
However, I suggest using String.Join and Linq instead of loop and let .Net do all the work for you:
// List has its own Reverse() method so we have to put Reverse<int>() to use Linq one
Console.Write(String.Join(" ", dso.Reverse<int>()));

Loop Through Every Possible Combination of an Array

I am attempting to loop through every combination of an array in C# dependent on size, but not order. For example: var states = ["NJ", "AK", "NY"];
Some Combinations might be:
states = [];
states = ["NJ"];
states = ["NJ","NY"];
states = ["NY"];
states = ["NJ", "NY", "AK"];
and so on...
It is also true in my case that states = ["NJ","NY"] and states = ["NY","NJ"] are the same thing, as order does not matter.
Does anyone have any idea on the most efficient way to do this?
The combination of the following two methods should do what you want. The idea is that if the number of items is n then the number of subsets is 2^n. And if you iterate from 0 to 2^n - 1 and look at the numbers in binary you'll have one digit for each item and if the digit is 1 then you include the item, and if it is 0 you don't. I'm using BigInteger here as int would only work for a collection of less than 32 items and long would only work for less than 64.
public static IEnumerable<IEnumerable<T>> PowerSets<T>(this IList<T> set)
{
var totalSets = BigInteger.Pow(2, set.Count);
for (BigInteger i = 0; i < totalSets; i++)
{
yield return set.SubSet(i);
}
}
public static IEnumerable<T> SubSet<T>(this IList<T> set, BigInteger n)
{
for (int i = 0; i < set.Count && n > 0; i++)
{
if ((n & 1) == 1)
{
yield return set[i];
}
n = n >> 1;
}
}
With that the following code
var states = new[] { "NJ", "AK", "NY" };
foreach (var subset in states.PowerSets())
{
Console.WriteLine("[" + string.Join(",", subset.Select(s => "'" + s + "'")) + "]");
}
Will give you this output.
[]
['NJ']
['AK']
['NJ','AK']
['NY']
['NJ','NY']
['AK','NY']
['NJ','AK','NY']
You can use back-tracking where in each iteration you'll either (1) take the item in index i or (2) do not take the item in index i.
Pseudo code for this problem:
Main code:
Define a bool array (e.g. named picked) of the length of states
Call the backtracking method with index 0 (the first item)
Backtracking function:
Receives the states array, its length, the current index and the bool array
Halt condition - if the current index is equal to the length then you just need to iterate over the bool array and for each item which is true print the matching string from states
Actual backtracking:
Set picked[i] to true and call the backtracking function with the next index
Set picked[i] to false and call the backtracking function with the next index

How to find subset of numbers in array that equals to 10? [duplicate]

This question already has answers here:
Find if pair of elements with given sum exists in large integer array
(6 answers)
Closed 8 years ago.
I want to find the sum of all subsets of adjacent numbers.
So if the set is 6 1 2 2 5
I want to find (the sum of)
6 1 2 2 5
6 1 2 2
1 2 2 5
6 1 2
1 2 2
2 2 5
6 1
1 2
2 2
2 5
So I want to find not anly subsets of 2 numbers,but more(example input: 6 1 2 2 5 -> 6+2+2=10 or 1+2+2+5=10) and print them.
using System;
class Subset
{
static void Main()
{
string[] num = Console.ReadLine().Split(' ');
int[] number = new int[num.Length];
for (int a = 0; a < 5; a++)
{
number[a] = Convert.ToInt32(num[a]);
}
int sum;
bool found = false;
for (int i = 0; i < 5; i++)
{
sum = 0;
for (int j = i; j < 5; j++)
{
sum = sum + number[j];
if (sum == 10)
{
found = true;
for (int k = i; k < j; k++)
{
Console.Write("{0} + ", number[k]);
}
Console.Write(number[j]);
Console.Write(" = 10\n");
}
}
}
if (found == false)
{
Console.WriteLine("no zero subset\n\n");
}
}
}
This is very similar to the subset sum problem. The only way to really find a combination that adds up to ten (or even all combinations), you will have to test all combinations. I am not sure if you want combinations of any size, or only two numbers. The examples you give only involve examples where two numbers add up to ten, which can be easily done by checking for all pairs.
for (int i = 1; i < numbers.Length; i++)
for (int j = 0, j < i; j++)
if (numbers[i] + numbers[j] == 10)
{
Console.WriteLine("{0} + {1} = 10", numbers[i], numbers[j];
return;
}
Console.WriteLine("no subset that sums up to 10");
If however you want to find any subset of numbers that add up to ten, you have to consider all subsets of the set you are given. The best way to do this is using dynamic programming. You loop through the array of numbers and for each number you make the decision to either include the element in the subset or not. Let's look at the following method:
bool SubsetSum(int[] numbers, int startIndex, int sum)
{
if (startIndex == numbers.Length - 1) // base case, only one element to consider
return numbers[startIndex] == sum || sum = 0;
return SubsetSum(numbers, startIndex + 1, sum) // don't take the current element
|| SubsetSum(numbers, startIndex + 1, sum - numbers[startIndex]; // take the current element
}
This method first checks if we arrived at the last element. In that case, we have two easy cases to consider: the sum we want to reach is 0, so we don't take the element, or the sum we want to reach is equal to the last element, in which case we do take it. Otherwise, there is no valid solution.
In all the other cases, we just branch into two paths, either taking or not taking the element into the subset.
This algorithm will run in exponential time in the amount of numbers as input. You can speed this up by using memorisation. You can create a huge table and save for every pair of startIndex and sum the outcome value. That way you are sure you will never evaluate the same thing twice. (Look up dynamic programming to learn more about this)
The method I described above only returns if a subset exists. To actually find the subset, you will also have to pass back the indices of the elements you have added to the subset. I won't work that out, as it makes the thing a lot more complicated. If you use a table in the dynamic programming approach, you are also able to use some backtracking techniques to find the right indices in linear time.

Categories

Resources