I have one list. I want check if list[i] contains string "6 1". But this code thinks 6 13 24 31 35 contains "6 1". Its false.
6 13 24 31 35
1 2 3 6 1
stringCheck = "6 1";
List<string> list = new List<string>();
list.Add("6 13 24 31 35");
list.Add("1 2 3 6 1");
for (int i=0; i<list.Count; i++)
{
if (list[i].Contains(stringCheck)
{
// its return me two contains, but in list i have one
}
}
But this code thinks 6 13 24 31 35 contains "6 1". Its false. […]
List<string> list = new List<string>();
list.Add("6 13 24 31 35");
list.Add("1 2 3 6 1");
No, it's true because you are dealing with sequences of characters, not sequences of numbers here, so your numbers get treated as characters.
If you really are working with numbers, why not reflect that in the choice of data type chosen for your list?:
// using System.Linq;
var xss = new int[][]
{
new int[] { 6, 13, 24, 31, 35 },
new int[] { 1, 2, 3, 6, 1 }
};
foreach (int[] xs in xss)
{
if (xs.Where((_, i) => i < xs.Length - 1 && xs[i] == 6 && xs[i + 1] == 1).Any())
{
// list contains a 6, followed by a 1
}
}
or if you prefer a more procedural approach:
foreach (int[] xs in xss)
{
int i = Array.IndexOf(xs, 6);
if (i >= 0)
{
int j = Array.IndexOf(xs, 1, i);
if (i + 1 == j)
{
// list contains a 6, followed by a 1
}
}
}
See also:
Finding a subsequence in longer sequence
Find sequence in IEnumerable<T> using Linq
Related
I have a set of typed elements and price for each type
var array = new []
{
new Elem(0, Types.LowCost),
new Elem(1, Types.MediumCost),
new Elem(2, Types.MediumCost),
new Elem(3, Types.HightCost),
}
And prices: LowCost - 3, MediumCost - 5, HightCost - 9
How would you find all possible unique combinations of elements with restriction "sum of costs for all elements doesn't exceed a restriction"?
For example for MaxCost = 13 I expect
Elem(0) //cost 3
Elem(1) // 5
Elem(2) // 5
Elem(3) // 9
Elem(0), Elem(1) //cost 3+5=8
Elem(0), Elem(2) // 3+5=8
Elem(0), Elem(3) // 3+9=12
Elem(1), Elem(2) // 5+5 = 10
Elem(0), Elem(1), Elem(2) // cost 13
Given a dictionary of costs:
public Dictionary<Types, int> costs = new Dictionary<Types, int>()
{
{ Types.LowCost, 3 },
{ Types.MediumCost, 5 },
{ Types.HightCost, 9 },
};
I can do this:
var query =
from n in Enumerable.Range(0, 1 << array.Length).Skip(1)
let combination = array.Where((x, i) => ((n >> i) & 1) == 1).ToArray()
let cost = combination.Select(x => costs[x.Type]).Sum()
where cost <= 13
select String.Join(", ", combination.Select(x => x.Id));
That gives me:
0
1
0, 1
2
0, 2
1, 2
0, 1, 2
3
0, 3
To explain in more detail. I need to take a bunch of numbers and place them in classes/groups. Lets say I have 100 numbers. I need to divide that by the number of classes (n) where n = 3 and place them in three groups with 33, 33, 34 numbers respectively. or if (n) = 4 then it would be 4 classes of 25, 25, 25, 25. They also need to stay grouped from highest to lowest.
I have searched and saw a few things relating to LINQ to do this but I haven't wrapped my head around it.
I figured I could put all the numbers in a list, then find the total number in the index divide it by the number of classes to find out how many need to go into each class. My problem comes in is how to pull the numbers out of the list and place them in there respective groups while maintaining there grouping highest to lowest. Result desired for 3 classes with 15 numbers.
List<int> test = new List<int> { 100, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86 };
int total_indexes = test.Count + 1;
float classes = (total_indexes / 3);
Classes would equal 5 so it would look like this below
Class A:
100
99
98
97
96
Class B:
95
94
93
92
91
Class C:
90
89
88
87
86
Ok so I wrote this piece of code to give you the result you want:
public List<int[]> Do(int[] numbers, int groupCount)
{
numbers = numbers.OrderByDescending(x => x).ToArray();
var result = new List<int[]>();
var itemsCountInEachGroup = numbers.Length / groupCount;
var remainingCount = numbers.Length % groupCount;
var iterateCount = groupCount;
for (int i = 0; i < iterateCount; i++)
{
var skip = i * itemsCountInEachGroup;
//Last iterate
if (i == iterateCount - 1)
{
var n = numbers.Skip(skip).Take(itemsCountInEachGroup + remainingCount).ToArray();
result.Add(n);
}
else
{
var n = numbers.Skip(skip).Take(itemsCountInEachGroup).ToArray();
result.Add(n);
}
}
return result;
}
Example =>
var numbers = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };
var res = Do(numbers, 5);
This solution is probably not very optimized, and is likely to be improved.
int groupNb = 3, elementNb = 100;
//Populating elements with pseudo-random numbers for demonstration
Random r = new Random();
List<int> elements = new List<int>();
for (int i = 0; i < elementNb; i++)
elements.Add(r.Next(0, 100));
//The groups
List<int>[] groups = new List<int>[groupNb];
//Classifying elements in groups
int currentGroup = 0;
foreach (int value in elements.OrderByDescending(x => x))
{
if (groups[currentGroup] == null)
groups[currentGroup] = new List<int>();
groups[currentGroup].Add(value);
currentGroup = ++currentGroup % groupNb;
}
I did the answer with a PowerShell
open PowerShell ISE
and write the following script:
$Numbers = 100,94,91,90,89,85,84,81,79,74,74,70,95,92,83
$SortedNumbers = $Numbers | sort -Descending
$NumberofClasses = 3
$Countofnumbersinclase = $Numbers.Count / $NumberofClasses
$x = 0
$y = 0
For ($i = 0 ; $i -lt $NumberofClasses ;$i++){
$y = $i+$Countofnumbersinclase-1+$y
$Clasno = $i+1
Write-host "class No $Clasno is " $SortedNumbers[$X..$Y]
$x = $y+1
}
The result as following:
class No 1 is 100 95 94 92 91
class No 2 is 90 89 85 84 83
class No 3 is 81 79 74 74 70
I think exactly s you want and you can add any numbers or any no of classes and it will works
If all groups (with the only exception of the last one) should have equal number of items you can try Linq OrderBy followed by GroupBy:
Code:
using System.Linq;
...
private static List<T>[] Classify<T>(List<T> source, int count)
where T : IComparable<T> {
int size = source.Count / count;
return source
.OrderBy(item => item)
.Select((item, index) => new { item, index })
.GroupBy(pair => Math.Clamp(pair.index / size, 0, count - 1),
pair => pair.item)
.Select(group => group.ToList())
.ToArray();
}
If your C# version doesn't have Math.Clamp you can implement it as
private static int Clamp(int value, int min, int max) {
return value < min ? min :
value > max ? max :
value;
}
Demo:
// Let's split "count" items into "classes" classes
int count = 10;
int classes = 4;
List<int> demo = Enumerable
.Range(1, count)
.ToList();
var result = Classify(demo, classes);
string report = string.Join(Environment.NewLine, result
.Select(list => $"{list.First()} - {list.Last()} ({list.Count} items) : {string.Join(", ", list)}"));
Console.Write(report);
Outcome:
1 - 2 (2 items) : 1, 2
3 - 4 (2 items) : 3, 4
5 - 6 (2 items) : 5, 6
7 - 10 (4 items) : 7, 8, 9, 10
I have a list of key-value pairs of <string, int>. I want to merge and construct a new string with the keys that has close values (+3-3) and add each new string to a list.
Here are the keys and values of my list:
Luger: 9
Burger: 9
Le: 21
Pigeon: 21
Burger: 21
Hamburger: 25
Double: 30
Animal: 31
Style: 31
The: 43
Original: 43
Burger: 44
Here's the output that i want to achieve:
Luger Burger
Le Pigeon Burger
Hamburger
Double Animal Style
The Original Burger
To achieve this, firstly i created a list containing this key-value pairs. And iterate through each item and tried to find close values, assign them to new key-value pairs and delete that index. But that doesn't work properly. That's the code so far:
for (int i = 0; i < wordslist.Count; i++)
{
for (int j = 0; j < wordslist.Count; j++)
{
if (wordslist[i].Value <= wordslist[j].Value + 3 && wordslist[i].Value >= wordslist[j].Value - 3)
{
wordslist.Add(
new KeyValuePair<string, int>(wordslist[i].Key + " " + wordslist[j].Key, wordslist[i].Value)
);
wordslist.RemoveAt(j);
}
}
wordslist.RemoveAt(i);
}
this doesn't work and produce repetitive results as below:
Pigeon: 21
Style: 30
Burger: 30
Double Double Animal: 30
Burger Burger: 31
Original Original The The Original Burger Original Burger: 42
Is there any algorithm that can iterate through these items and construct a string by merging the keys that has close values and add each item to a list?
You can simplify this logic:
public IEnumerable<string> GetPlusOrMinus3(Dictionary<string, int> fullList, int checkNumber)
{
return fullList.Where(w => checkNumber <= w.Value + 3
&& checkNumber >= w.Value - 3)
.Select(s => $"{s.Key}: {s.Value}" );
}
The string format isn't perfect for you, but the logic should hold.
And in use you could do something like:
var forOne = GetPlusOrMinus3(values, 1);
var resultString = String.Join(", ", forOne);
Console.WriteLine(resultString);
Which would write out:
one: 1, two: 2, four: 4
And to loop through everything:
foreach(var entryValue in values.Values)
{
Console.WriteLine(String.Join(", ", GetPlusOrMinus3(values, entryValue)));
}
Or to loop through anything without resusing any results:
var matchedNumbers = new List<int>();
foreach(var entryValue in values.Values)
{
var matchResults = values.Where(w => entryValue <= w.Value + 3 && entryValue >= w.Value - 3
&& !matchedNumbers.Contains(w.Value)).ToDictionary(x => x.Key, x => x.Value);
if (matchResults.Any())
{
matchedNumbers.AddRange(matchResults.Select(s => s.Value).ToList());
Console.WriteLine(String.Join(", ",
GetPlusOrMinus3(matchResults, entryValue)));
}
}
Logs:
one: 1, two: 2, four: 4
twelve: 12, 10: 10, eleven: 11
six: 6
I have a text file that include of numbers and I save it in a string array.
one line of my text file is this:
2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114:275:5 8 1 14 10 6 10 18 12 25 7 40 1 30 18 8 2 1 5 21 10 2 21
every line save in one of indexes of string array.
now how can i access array elements as int type and search and calculate in all of array?
this is my array:
string [] lines = File.ReadAllLines(txtPath.Text);
for example I want to return indexes of array that include number'14' in all of array .
This is the easiest and clearest way to solve it. I commented so you can better understand what happens in the entire program.
class Program
{
static void Main(string[] args)
{
// this is your array of strings (lines)
string[] lines = new string[1] {
"2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114:275:5 8 1 14 10 6 10 18 12 25 7 40 1 30 18 8 2 1 5 21 10 2 21"
};
// this dictionary contains the line index and the list of indexes containing number 14
// in that line
Dictionary<int, List<int>> dict = new Dictionary<int, List<int>>();
// iterating over lines array
for (int i = 0; i < lines.Length; i++)
{
// creating the list of indexes and the dictionary key
List<int> indexes = new List<int>();
dict.Add(i, indexes);
// splitting the line by space to get numbers
string[] lineElements = lines[i].Split(' ');
// iterating over line elements
for (int j = 0; j < lineElements.Length; j++)
{
int integerNumber;
// checking if the string lineElements[j] is a number (because there also this case 114:275:5)
if (int.TryParse(lineElements[j], out integerNumber))
{
// if it is we check if the number is 14, in that case we add that index to the indexes list
if (integerNumber == 14)
{
indexes.Add(j);
}
}
}
}
// Printing out lines and indexes:
foreach (int key in dict.Keys)
{
Console.WriteLine(string.Format("LINE KEY: {0}", key));
foreach (int index in dict[key])
{
Console.WriteLine(string.Format("INDEX ELEMENT: {0}", index));
}
Console.WriteLine("------------------");
}
Console.ReadLine();
}
}
UPDATE 1:
As you requested:
special thanks for your clear answering.if i want to do search for all of my array elements what can i do? it means instead of only
number'14' i want to print indexes of all numbers that appear in
indexes
If you want to print all the indexes you should Console.WriteLine(j), that is the index of the inner for cycle, instead of checking the number value if (integerNumber == 14).
So, this is the program:
class Program
{
static void Main(string[] args)
{
// this is your array of strings (lines)
string[] lines = new string[1] {
"2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114:275:5 8 1 14 10 6 10 18 12 25 7 40 1 30 18 8 2 1 5 21 10 2 21"
};
// this dictionary contains the line index and the list of indexes containing number 14
// in that line
Dictionary<int, List<int>> dict = new Dictionary<int, List<int>>();
// iterating over lines array
for (int i = 0; i < lines.Length; i++)
{
// creating the list of indexes and the dictionary key
List<int> indexes = new List<int>();
dict.Add(i, indexes);
// splitting the line by space to get numbers
string[] lineElements = lines[i].Split(' ');
// iterating over line elements
for (int j = 0; j < lineElements.Length; j++)
{
// printing all indexes of the current line
Console.WriteLine(string.Format("Element index: {0}", j));
}
}
Console.ReadLine();
}
}
UPDATE 2:
As you requested:
if i want to search my line till first " : " apper and then search next line, what can i do?
You need to break the for cycle when you are on the element with :
class Program
{
static void Main(string[] args)
{
// this is your array of strings (lines)
string[] lines = new string[1] {
"2 3 9 14 23 26 34 36 39 40 52 55 59 63 67 76 85 86 90 93 99 108 114:275:5 8 1 14 10 6 10 18 12 25 7 40 1 30 18 8 2 1 5 21 10 2 21"
};
// this dictionary contains the line index and the list of indexes containing number 14
// in that line
Dictionary<int, List<int>> dict = new Dictionary<int, List<int>>();
// iterating over lines array
for (int i = 0; i < lines.Length; i++)
{
// creating the list of indexes and the dictionary key
List<int> indexes = new List<int>();
dict.Add(i, indexes);
// splitting the line by space to get numbers
string[] lineElements = lines[i].Split(' ');
// iterating over line elements
for (int j = 0; j < lineElements.Length; j++)
{
// I'm saving the content of lineElements[j] as a string
string element = lineElements[j];
// I'm checking if the element saved as string contains the string ":"
if (element.Contains(":"))
{
// If it does, I'm breaking the cycle, and I'll continue with the next line
break;
}
int integerNumber;
// checking if the string lineElements[j] is a number (because there also this case 114:275:5)
if (int.TryParse(lineElements[j], out integerNumber))
{
// if it is we check if the number is 14, in that case we add that index to the indexes list
if (integerNumber == 14)
{
indexes.Add(j);
}
}
}
}
// Printing out lines and indexes:
foreach (int key in dict.Keys)
{
Console.WriteLine(string.Format("LINE KEY: {0}", key));
foreach (int index in dict[key])
{
Console.WriteLine(string.Format("INDEX ELEMENT: {0}", index));
}
Console.WriteLine("------------------");
}
Console.ReadLine();
}
}
As you can see, if you run this piece of code and compare it with the first version, in output you'll get only the index of the first 14 occurrence, because the second one is after the string with :.
First you must get all conttent of file in the string array format:
public string[] readAllInFile(string filepath){
var lines = File.ReadAllLines(path);
var fileContent = string.Join(' ',lines);//join all lines of file content in one variable
return fileContent.Split(' ');//each word(in your case each number) in one index of array
}
and in usage time you can do like this:
var MyFileContent = readAllInFile(txtPath.Text);
int x= Convert.ToInt32(MyFileContent[2]);
IEnumerable<int> numbers = MyFileContent.Select(m=> int.Parse(m);)
var sumeOf = numbers.sum();
you can use linq to have more tools on collections.
var linesAsInts = lines.Select(x => x.Split(' ').Select(int.Parse));
var filteredLines = linesAsInts.Where(x => x.Contains(14));
// define value delimiters.
var splitChars = new char[] { ' ', ':' };
// read lines and parse into enumerable of enumerable of ints.
var lines = File.ReadAllLines(txtPath.Text)
.Select(x => x.Split(splitChars)
.Select(int.Parse));
// search in array.
var occurences = lines
.Select((line,lineIndex) => line
.Select((integer, integerIndex) => new { integer, integerIndex })
.Where(x => x.integer == 10)
.Select(x => x.integerIndex));
// calculate all of array.
var total = lines.Sum(line => line.Sum());
I have a nested List<List<int>> data structure, and I would like to iterate over every possible combination of the inmost int elements, such as that in each combination exactly one value from each inner List<int> is used. For example, please consider the following nested list:
var listOfLists = new List<List<int>>()
{
new List<int>() { 1, 2, 3, 4, 9 },
new List<int>() { 0, 3, 4, 5 },
new List<int>() { 1, 6 }
};
The first few combinations would yield:
1 0 1 // Indices: 0 0 0
1 0 6 // Indices: 0 0 1
1 3 1 // Indices: 0 1 0
1 3 6 // Indices: 0 1 1
2 0 1 // Indices: 1 0 0
2 0 6 // Indices: 1 0 1
2 3 1 // Indices: 1 1 0
...
How could I accomplish this?
My initial approach was to make permutations of indices, but the lengths of inner List<int> lists are not necessarily equal. Another approach I can think of is multiplying the length of each inner List<int>, then using the modulo and division operators combined with Math.Floor to determine indices, but I'm not sure how exactly this could be implemented when N collections are present.
I've answered a several similar questions, which all basically use a variation of one and the same algorithm. Here is the modified version of the Looking at each combination in jagged array:
public static class Algorithms
{
public static IEnumerable<T[]> GetCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
{
var result = new T[input.Count];
var indices = new int[result.Length];
for (int pos = 0, index = 0; ;)
{
for (; pos < result.Length; pos++, index = 0)
{
indices[pos] = index;
result[pos] = input[pos][index];
}
yield return result;
do
{
if (pos == 0) yield break;
index = indices[--pos] + 1;
}
while (index >= input[pos].Count);
}
}
}
Note that in order to not do allocation, the above method yields one and the same array instance. This is perfect if you want just to count or process it with foreach loop or LINQ query without storing the results. For instance:
foreach (var combination in listOfLists.GetCombinations())
{
// do something with the combination
}
If you indeed need to store the results, you can always use ToList:
var allCombinations = listOfLists.GetCombinations().Select(c => c.ToList()).ToList();
How about using LINQ?
var listOfLists = new List<List<int>>()
{
new List<int>() { 1, 2, 3, 4, 9 },
new List<int>() { 0, 3, 4, 5 },
new List<int>() { 1, 6 }
};
var result = from l in listOfLists[0]
from y in listOfLists[1]
from z in listOfLists[2]
select new List<int>()
{
l,
y,
z
};
This will of course only work for this specific list as there are 3 lists in your list of lists.