Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I wish I could use this code with strings instead of integers
public static List<int> EvenlyDistribute(List<int> list)
{
List<int> original = list;
Dictionary<int, int> dict = new Dictionary<int, int>();
list.ForEach(x => dict[x] = dict.Keys.Contains(x) ? dict[x] + 1 : 1);
list = list.Where(x => dict[x] == 1).ToList();
foreach (int key in dict.Where(x => x.Value > 1).Select(x => x.Key))
{
int iterations = original.Where(x => x == key).Count();
for (int i = 0; i < iterations; i++)
list.Insert((int)Math.Ceiling((decimal)((list.Count + iterations) / iterations)) * i, key);
}
return list;
}
Usage in main:
List<int> test = new List<int>() {11,11,11,13,14,15,16,17,18,19,19,19,19};
List<int> newList = EvenlyDistribute(test);
Output:
19,11,13,19,14,11,19,15,16,19,11,17,18
is it possible to use this method but using strings?
You can replace int with a generic type and replace the == with .Equals so that it will work with any type (including strings):
public static List<T> EvenlyDistribute<T>(List<T> input)
{
if (input == null || input.Count < 3) return input;
var dict = input.Distinct().ToDictionary(
key => key, value => input.Count(x => x.Equals(value)));
input = input.Where(x => dict[x] == 1).ToList();
foreach (var kvp in dict.Where(item => item.Value > 1))
{
decimal count = kvp.Value;
for (var i = 0; i < count; i++)
{
input.Insert((int) (Math.Ceiling((input.Count + count) / count) * i),
kvp.Key);
}
}
return input;
}
Try following :
class Program
{
static void Main(string[] args)
{
List<int> test = new List<int>() { 11, 11, 11, 13, 14, 15, 16, 17, 18, 19, 19, 19, 19 };
List<int> newList = EvenlyDistribute(test);
}
static List<int> EvenlyDistribute(List<int> input)
{
List<int> results = new List<int>();
var groups = input.GroupBy(x => x).OrderByDescending(x => x.Count());
int max = groups.First().Count();
for (int i = max - 1; i >= 0; i--)
{
foreach (var group in groups)
{
if (group.Count() - 1 >= i)
{
results.Add(group.Skip(i - 1).First());
}
}
}
return results;
}
}
Related
How can I display only 3 consecutive numbers for example in my code below I only want it to return 4, as that appears 3 times.
9 is 4 times so do not want that and 7 is twice so not what want that.
The code I currently have display 9
int[] intArray = { 9, 9, 9, 9, 6, 4, 4, 4, 7, 7 };
var adjacentDuplicateNumbers = intArray
.Skip(1)
.Where((value, index) => value == intArray[index])
.Distinct();
var enumerable = adjacentDuplicateNumbers as int[] ?? adjacentDuplicateNumbers.ToArray();
if (enumerable.Any())
{
Console.WriteLine("{0} is a consecutive number and is repeated 3 times.", enumerable.First());
}
else
{
Console.WriteLine("no consecutive number found.");
}
Using the extension method of this post: LINQ to find series of consecutive numbers
public static IEnumerable<IEnumerable<T>> GroupWhile<T>(this IEnumerable<T> seq, Func<T, T, bool> condition)
{
T prev = seq.First();
List<T> list = new List<T>() { prev };
foreach (T item in seq.Skip(1))
{
if (condition(prev, item) == false)
{
yield return list;
list = new List<T>();
}
list.Add(item);
prev = item;
}
yield return list;
}
Usage:
var res = intArray.GroupWhile((a, b) => a == b).
Where(x => x.Count() == 3).Select(x => x.First());
Sometimes a simple foor loop is enough (and should be faster than linq)
int[] intArray = { 9, 9, 9, 9, 6, 4, 4, 4, 7, 7 };
var minus2 = intArray[0];
var minus1 = intArray[1];
var result = new List<int>();
for(int i = 2; i < intArray.Length; i++)
{
var current = intArray[i];
if(minus2 == minus1 && minus1 == current)
{
result.Add(current);
}
minus2 = minus1;
minus1 = current;
}
var results = intArray.Distinct()
.ToDictionary(k => k, v => intArray.Count(x => x == v))
.Where(x => x.Value == 3)
.Select(x => x.Key);
Take the district elements in the array. Use these as keys in a dictionary that map to the number of occurrences of this key in the original array. Use Where to only select pairs that match the required count (3). Use Select to return the resulting keys - in this example only 4.
I have two arrays and i am trying to get all possible sum of each element with other element of two array and index of each element
int[] width = new int[2] {10,20 };
int[] height = new int[2] {30,40 };
result should like this (value / indexes)
10 width0
10+20 width0+width1
10+30 width0+height0
10+40 width0+height1
10+20+30 width0+width1+height0
10+20+40 width0+width1+height1
10+20+30+40 width0+width1+height0+height1
And so for each element in two array
I tried using permutation but I get other output
It is more easy to get all combinations from one array than two arrays. And as we see, you need to store indices and array names along with the value of the elements in collections. So, in my opinion the best option is to combine these two arrays in one dictionary, where the key will be the value of the numbers and the value will be [ArrayName + Index of item] (f.e width0, height1 and so on....)
So, let's combine these arrays in one dictionary:
int[] width = new int[2] { 10, 20 };
int[] height = new int[2] { 30, 40 };
var widthDictionary = width.ToList().Select((number, index) => new { index, number })
.ToDictionary(key => key.number, value => string.Format("width{0}", value.index));
var heightDictionary = height.ToList().Select((number, index) => new { index, number })
.ToDictionary(key => key.number, value => string.Format("height{0}", value.index));
// And here is the final dictionary
var totalDictionary = widthDictionary.Union(heightDictionary);
Then add this method to your class: (source)
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Then send your dictionary as an argument to this method and project this collection as you want with the help of the Select() method:
var sumOfCombinations = GetPowerSet(totalDictionary.ToList())
.Where(x => x.Count() > 0)
.Select(x => new
{
Numbers = x.Select(pair => pair.Key).ToList(),
DisplayValues = x.Select(pair => pair.Value).ToList()
})
.ToList();
And at the end you can display expected result as this:
sumOfCombinations.ForEach(x =>
{
x.Numbers.ForEach(number => Console.Write("{0} ", number));
x.DisplayValues.ForEach(displayValue => Console.Write("{0} ", displayValue));
Console.WriteLine();
});
And, the result is:
This is a play off of #Farhad Jabiyev's answer.
Declares a class called IndexValuePair. and uses foreach on widthList and heightList. to populate the 'Index' property of item instance.
Note: Index is a string.
Class & Static Function
public class IndexValuePair
{
public string Index {get;set;}
public int Value {get;set;}
}
public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
return from m in Enumerable.Range(0, 1 << list.Count)
select
from i in Enumerable.Range(0, list.Count)
where (m & (1 << i)) != 0
select list[i];
}
Main (Console)
static void Main(string[] args)
{
int[] width = new int[2] { 10, 20 };
int[] height = new int[2] { 30, 40 };
var wholeList = width.Select(val => new IndexValuePair() { Index = "width", Value = val }).ToList();
var heightList = height.Select(val => new IndexValuePair() { Index = "height", Value = val }).ToList();
var iteration = 0;
wholeList.ForEach(ivp => { ivp.Index = ivp.Index + count; count = iteration + 1; });
iteration = 0;
heightList.ForEach(ipv => { ivp.Index = ivp.Index + count; count = iteration + 1; });
wholeList.AddRange(heightList);
var sumOfCombinations = GetPowerSet(wholeList).Where(x => x.Count() > 0)
.Select(x => new { Combination = x.ToList(), Sum = x.Sum(ivp => ivp.Value) }).ToList();
StringBuilder sb = new StringBuilder();
sumOfCombinations.ForEach(ivp =>
{
ivp.Combination.ForEach(pair => sb.Append(string.Format("{0} ", pair.Value)));
sb.Append(string.Format("= {0} = ", x.Sum));
ivp.Combination.ForEach(pair=> sb.Append(string.Format("{0} + ", pair.Index)));
sb.Length -= 3;
Console.WriteLine(sb);
sb.Clear();
});
var key = Console.ReadKey();
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I have an array: options[15,12,52,a,12,15,abc,15] and I need to count options.
Example:
counts[15]:3 or counts[12]:2 ...
I need this in C#. How can I do this?
Thank you for your answers. My solution is here:
Dictionary<object, int> counts = new Dictionary<object, int>();
for (var t = 0; t < voters_options.GetLength(0); t++) {
if (voters_options[t] != null) {
if (!counts.ContainsKey(voters_options[t]))
counts[voters_options[t]] = 1;
else
counts[voters_options[t]] = 1 + counts[voters_options[t]];
}
}
For C# begginer:
using System;
using System.Collections.Generic;
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
object[] options = { 15, 12, 52, "a", 12, 15, "abc", 15 };
Dictionary<object, int> counts = new Dictionary<object, int>();
for (var t = 0; t < options.GetLength(0); t++)
{
if (!counts.ContainsKey(options[t]))
counts[options[t]] = 1;
else
counts[options[t]] = 1 + counts[options[t]];
}
foreach (var entry in counts)
Console.Out.WriteLine("Key: " + entry.Key + "; Count: " + entry.Value.ToString());
}
}
}
Results are:
Key: 15; Count: 3
Key: 12; Count: 2
Key: 52; Count: 1
Key: a; Count: 1
Key: abc; Count: 1
You can use LINQ grouping:
string[] options = { "15", "12", "52", "a", "12", "15", "abc", "15" };
var groupedOptions = options.GroupBy(o => o)
.ToDictionary(g => g.Key, g => g.Count());
foreach (var groupedOption in groupedOptions)
Console.WriteLine("{0} : {1}", groupedOption.Key, groupedOption.Value);
Try this with linq in c#:
var groups = arr1.GroupBy(item => item);
foreach (var group in groups)
{
Console.WriteLine(string.Format("{0} occurences of {1}", group.Count(), group.Key);
}
Counting occurrences in Array
Here's a traditional approach.
var options = new [] {"15","12","52","a","12","15","abc","15"};
Dictionary<string, int> counts = new Dictionary<string, int>();
foreach(var t in options)
{
if(counts.ContainsKey(t))
counts[t]++;
else
counts[t] = 1;
}
You can use a dictionary to count the elements.
public ConcurrentDictionary<string, int> CountOptions(int[] options)
{
ConcurrentDictionary<string, int> counts = new ConcurrentDictionary<string, int>();
for (var t = 0; t < options.Length; t++)
{
counts.AddOrUpdate(options[t].ToString(), 1, (k, v) => v + 1);
}
return counts;
}
I'm trying to convert a simple piece of Math to Linq.
I want to bundle together the prime factors for several numbers into one collection.
Consider the following integers.
8 = 2 * 2 * 2
12 = 2 * 2 * 3
The smallest number divisible by both 8 & 12 is 24, so I'd like the resultant group to contain
{ 2, 2, 2, 3 }
If I use Concat the result is {2,2,2,2,2,3} - not correct
If I use Union the result is {2,3} - not correct
Is there a built in Linq Set Manipulation function which will recognise that it needs to keep the maximum number of occurences of an item (i.e. not add another if there are already enough there to satisfy if & add another if there aren't)
Well, it's not any existing function, as I don't think such exists, but pretty simple code is capable of handling this:
var listA = new List<int> {2, 2, 2};
var listB = new List<int> {2, 2, 3};
var grouppedA = listA.GroupBy(i => i).Select(g => new { key = g.Key, count = g.Count()});
var grouppedB = listB.GroupBy(i => i).Select(g => new { key = g.Key, count = g.Count()});
var result = grouppedA
.Union(grouppedB)
.GroupBy(g => g.key)
.SelectMany(g => Enumerable.Repeat(g.Key, g.Max(h => h.count)));
foreach (int i in result)
{
Console.Write(i + " ");
}
Console.ReadKey();
Output:
2 2 2 3
using System;
using System.Collections.Generic;
public class Sample {
public static void Main(String[] args) {
var n8 = toFactors(8);
var n12 = toFactors(12);
var uf = unionFactors(n8, n12);//LCM
printFactors(uf);
}
public static void printFactors(Dictionary<long, int> factors){
Console.Write("{ ");
foreach(var factor in factors.Keys){
for(int i=0;i<factors[factor];++i)
Console.Write( factor + " ");
}
Console.WriteLine("}");
}
public static Dictionary<long, int> unionFactors(Dictionary<long, int> af, Dictionary<long, int> bf){
Dictionary<long, int> uf = new Dictionary<long, int>();
foreach(var kv in af){
uf.Add(kv.Key, kv.Value);//copy
}
foreach(var kv in bf){
if(uf.ContainsKey(kv.Key)){
if(kv.Value > uf[kv.Key])//max
uf[kv.Key] = kv.Value;
} else {
uf.Add(kv.Key, kv.Value);
}
}
return uf;
}
public static Dictionary<long, int> toFactors(long num){
var factors = new Dictionary<long, int>();
long n = num, i = 2, sqi = 4;
while(sqi <= n){
while(n % i == 0){
n /= i;
if(factors.ContainsKey(i)){
factors[i] += 1;
} else {
factors.Add(i, 1);
}
}
sqi += 2 * (i++) + 1;
}
if(n != 1 && n != num){
if(factors.ContainsKey(i)){
factors[i] += 1;
} else {
factors.Add(i, 1);
}
}
if(factors.Count == 0)
factors.Add(num, 1);//prime
return factors;
}
}
This question already has answers here:
C# LINQ find duplicates in List
(13 answers)
Closed 3 years ago.
I have a List<string> which has some words duplicated. I need to find all words which are duplicates.
Any trick to get them all?
In .NET framework 3.5 and above you can use Enumerable.GroupBy which returns an enumerable of enumerables of duplicate keys, and then filter out any of the enumerables that have a Count of <=1, then select their keys to get back down to a single enumerable:
var duplicateKeys = list.GroupBy(x => x)
.Where(group => group.Count() > 1)
.Select(group => group.Key);
If you are using LINQ, you can use the following query:
var duplicateItems = from x in list
group x by x into grouped
where grouped.Count() > 1
select grouped.Key;
or, if you prefer it without the syntactic sugar:
var duplicateItems = list.GroupBy(x => x).Where(x => x.Count() > 1).Select(x => x.Key);
This groups all elements that are the same, and then filters to only those groups with more than one element. Finally it selects just the key from those groups as you don't need the count.
If you're prefer not to use LINQ, you can use this extension method:
public void SomeMethod {
var duplicateItems = list.GetDuplicates();
…
}
public static IEnumerable<T> GetDuplicates<T>(this IEnumerable<T> source) {
HashSet<T> itemsSeen = new HashSet<T>();
HashSet<T> itemsYielded = new HashSet<T>();
foreach (T item in source) {
if (!itemsSeen.Add(item)) {
if (itemsYielded.Add(item)) {
yield return item;
}
}
}
}
This keeps track of items it has seen and yielded. If it hasn't seen an item before, it adds it to the list of seen items, otherwise it ignores it. If it hasn't yielded an item before, it yields it, otherwise it ignores it.
and without the LINQ:
string[] ss = {"1","1","1"};
var myList = new List<string>();
var duplicates = new List<string>();
foreach (var s in ss)
{
if (!myList.Contains(s))
myList.Add(s);
else
duplicates.Add(s);
}
// show list without duplicates
foreach (var s in myList)
Console.WriteLine(s);
// show duplicates list
foreach (var s in duplicates)
Console.WriteLine(s);
If you're looking for a more generic method:
public static List<U> FindDuplicates<T, U>(this List<T> list, Func<T, U> keySelector)
{
return list.GroupBy(keySelector)
.Where(group => group.Count() > 1)
.Select(group => group.Key).ToList();
}
EDIT: Here's an example:
public class Person {
public string Name {get;set;}
public int Age {get;set;}
}
List<Person> list = new List<Person>() { new Person() { Name = "John", Age = 22 }, new Person() { Name = "John", Age = 30 }, new Person() { Name = "Jack", Age = 30 } };
var duplicateNames = list.FindDuplicates(p => p.Name);
var duplicateAges = list.FindDuplicates(p => p.Age);
foreach(var dupName in duplicateNames) {
Console.WriteLine(dupName); // Will print out John
}
foreach(var dupAge in duplicateAges) {
Console.WriteLine(dupAge); // Will print out 30
}
Using LINQ, ofcourse.
The below code would give you dictionary of item as string, and the count of each item in your sourc list.
var item2ItemCount = list.GroupBy(item => item).ToDictionary(x=>x.Key,x=>x.Count());
For what it's worth, here is my way:
List<string> list = new List<string>(new string[] { "cat", "Dog", "parrot", "dog", "parrot", "goat", "parrot", "horse", "goat" });
Dictionary<string, int> wordCount = new Dictionary<string, int>();
//count them all:
list.ForEach(word =>
{
string key = word.ToLower();
if (!wordCount.ContainsKey(key))
wordCount.Add(key, 0);
wordCount[key]++;
});
//remove words appearing only once:
wordCount.Keys.ToList().FindAll(word => wordCount[word] == 1).ForEach(key => wordCount.Remove(key));
Console.WriteLine(string.Format("Found {0} duplicates in the list:", wordCount.Count));
wordCount.Keys.ToList().ForEach(key => Console.WriteLine(string.Format("{0} appears {1} times", key, wordCount[key])));
I'm assuming each string in your list contains several words, let me know if that's incorrect.
List<string> list = File.RealAllLines("foobar.txt").ToList();
var words = from line in list
from word in line.Split(new[] { ' ', ';', ',', '.', ':', '(', ')' }, StringSplitOptions.RemoveEmptyEntries)
select word;
var duplicateWords = from w in words
group w by w.ToLower() into g
where g.Count() > 1
select new
{
Word = g.Key,
Count = g.Count()
}
I use a method like that to check duplicated entrys in a string:
public static IEnumerable<string> CheckForDuplicated(IEnumerable<string> listString)
{
List<string> duplicateKeys = new List<string>();
List<string> notDuplicateKeys = new List<string>();
foreach (var text in listString)
{
if (notDuplicateKeys.Contains(text))
{
duplicateKeys.Add(text);
}
else
{
notDuplicateKeys.Add(text);
}
}
return duplicateKeys;
}
Maybe it's not the most shorted or elegant way, but I think that is very readable.
lblrepeated.Text = "";
string value = txtInput.Text;
char[] arr = value.ToCharArray();
char[] crr=new char[1];
int count1 = 0;
for (int i = 0; i < arr.Length; i++)
{
int count = 0;
char letter=arr[i];
for (int j = 0; j < arr.Length; j++)
{
char letter3 = arr[j];
if (letter == letter3)
{
count++;
}
}
if (count1 < count)
{
Array.Resize<char>(ref crr,0);
int count2 = 0;
for(int l = 0;l < crr.Length;l++)
{
if (crr[l] == letter)
count2++;
}
if (count2 == 0)
{
Array.Resize<char>(ref crr, crr.Length + 1);
crr[crr.Length-1] = letter;
}
count1 = count;
}
else if (count1 == count)
{
int count2 = 0;
for (int l = 0; l < crr.Length; l++)
{
if (crr[l] == letter)
count2++;
}
if (count2 == 0)
{
Array.Resize<char>(ref crr, crr.Length + 1);
crr[crr.Length - 1] = letter;
}
count1 = count;
}
}
for (int k = 0; k < crr.Length; k++)
lblrepeated.Text = lblrepeated.Text + crr[k] + count1.ToString();