Related
I have two lists.
First list contains values such as letters and numbers.
Length is [0]-[36].
Second list contains similar values and length is also [0]-[36].
I iterate second list twice with specific values to grab an Index key and when I grab Index key from second list, I want to remove items in first list based on Indexes from second one.
Problem is that second iteration doesn't work anymore, because index key has changed in first list.
I should probably convert list to an array (array has fixed index keys, list generates after) but I don't know how to add or remove index key from an array.
I don't use Linq.
Appreciate your help and suggestions
BR
Code sample:
List<int> list_z = new List<int>();
List<int> list_k = new List<int>();
for (int i = 0; i < second_list.Count; i++) {
if (second_list[i] == "K")
{
list_k.Add(i);
}
}
int k = list_k.Count;
for (int i = 0; i < k; i++) {
first_list.RemoveAt(list_k[i]);
}
for (int i = 0; i < second_list.Count; i++)
{
if (second_list[i] == "Z")
{
list_z.Add(i);
}
}
int z = list_z.Count;
for (int i = 0; i < svi_z; i++)
first_list.RemoveAt(lista_z[i]); //here is error, because first_list doesnt have index key number 36 anymore
}
When removing items from a list based on indexes, you should remove them in descending order (e.g. you should remove 11th, 8th, 3d, 2nd items - in this order). In your case:
list_k.Sort();
for (int i = list_k.Count - 1; i >= 0; --i)
first_list.RemoveAt(list_k[i]);
There is a simple solution for removing items from list at a specific index one after the other. That is to order the indexes descending, this way you'll not have any items moved around in the list.
Example:
The Below throws an error:
List<int> list = Enumerable.Range(0, 20).ToList();
List<int> indexesToRemove = new List<int>(){ 5, 13, 18 };
foreach(int i in indexesToRemove)
{
list.RemoveAt(i);
}
While if you do this, you'll get no error:
List<int> list = Enumerable.Range(0, 20).ToList();
List<int> indexesToRemove = new List<int>(){ 5, 13, 18 };
foreach(int i in indexesToRemove.OrderByDescending(x => x))
{
list.RemoveAt(i);
}
So in your case, you just need to call list_z = list_z.OrderByDescending(x => x).ToList(); before the loop and everything should work fine.
Or if you don't want to use linq you can do the following:
list_z.Sort((x, y) => y - x);
for (int i = 0; i < list_z.Count; i++)
first_list.RemoveAt(lista_z[i]);
}
Or you can simplify what your doing:
// Iterate and assign null
for (var i = 0; i < second_list.Count(); i++)
{
if (second_list[i] == "K")
{
first_list[i] = null;
}
}
// Iterate and assign null
for (var i = 0; i < second_list.Count; i++)
{
if (second_list[i] == "Z")
{
first_list[i] = null;
}
}
// remove nulls without linq or lambda
first_list.RemoveAll(delegate (string o) { return o == null; });
I am trying to solve a problem in testdome online exam.
the question is Write a function that, given a list and a target sum, returns zero-based indices of any two distinct elements whose sum is equal to the target sum. If there are no such elements, the function should return null.
here is my code , it is just 75% true and the 25% to time is exceed
using System;
using System.Linq;
using System.Collections.Generic;
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var result = from n1 in list
from n2 in list
where n1 + n2 == sum
select new Tuple<int, int>(list.IndexOf(n1), list.IndexOf(n2));
return result.FirstOrDefault();
}
public static void Main(string[] args)
{
Tuple<int, int> indices = FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12);
Console.WriteLine(indices.Item1 + " " + indices.Item2);
}
}
you can copy paste my code in the online website and see the result.
can any one help me so we get 100% true. :D
https://www.testdome.com/Questions/Csharp/TwoSum/4318
A little bit modification from Atif's solution which we don't need to copy the list to HashSet firstly.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
HashSet<int> hs = new HashSet<int>();
for (int i = 0; i < list.Count; i++)
{
var needed = sum - list[i];
if (hs.Contains(needed))
{
return Tuple.Create(list.IndexOf(needed), i);
}
hs.Add(list[i]);
}
return null;
}
This is one of those cases where you need to come at the problem from a different approach. Instead of doing a cross join of all the values and finding the first sum that matches, instead you want to make a lookup of all the values and loop through and check if the difference of the current item and the sum are in that lookup. That way you get a worst case of linear performance instead of polynomial.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var lookup = list.Select((x, i) => new { Index = i, Value = x })
.ToLookup(x => x.Value, x => x.Index);
for (int i = 0; i < list.Count; i++)
{
int diff = sum - list[i];
if (lookup.Contains(diff))
return Tuple.Create(i, lookup[diff].First());
}
return null;
}
A slight modification to your code by using a HashSet instead of a LookUp.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var hs = new HashSet<int>();
list.ToList().ForEach(x => hs.Add(x));
for (int i = 0; i < hs.Count; i++)
{
var diff = sum - list[i];
if (hs.Contains(diff))
{
var index = list.IndexOf(diff);
return new Tuple<int, int>(i, index);
}
}
return null;
}
I have tried and tested and get 100%, i.e. all tests pass including the
"Performance test with a large number of elements" test
public static Tuple<int, int> FindTwoSum(IList<int> list, int target)
{
var dict = new Dictionary<int, int>();
for (int i = 0; i < list.Count; i++)
{
var diff = target - list[i];
int j = -1;
if(dict.TryGetValue(diff, out j))
{
return Tuple.Create<int, int>(j, i);
}
dict[list[i]] = i;
}
return null;
}
This is my working solution:
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var dictionary = new Dictionary<int, int>();
for (var i = 0; i < list.Count; i++)
{
var aim = sum - list[i];
if(dictionary.ContainsKey(aim))
{
return new Tuple<int, int> (dictionary[aim], i);
}
else if(!dictionary.ContainsKey(list[i]))
{
dictionary.Add(list[i], i);
}
}
return null;
}
A slight modification to your version also passes the test. It is not 100% correct though. That tells you test cases on Testdome are not complete. I will leave it as an exercise as to what is wrong.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
var result = from n1 in list
join n2 in list
on n1 equals sum - n2
select new Tuple<int, int>(list.IndexOf(n1), list.IndexOf(n2));
return result.FirstOrDefault(x=>x.Item1!=x.Item2);
}
a non Linq extensions method using version of juharr's code
public static Tuple<int, int> FindTwoSumImprovedNonLinq(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
int diff = sum - list[i];
if (list.IndexOf(diff) > -1)
return Tuple.Create(i, list.IndexOf(diff));
}
return null;
}
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
int max = list.Max();
for (int i = 0; i < list.Count - 1; i++)
{
int first = list[i];
if (first + max == sum) return new Tuple<int, int>(i, list.IndexOf(max));
if (first + max < sum) continue;
for (int j = i+1; j < list.Count; j++)
{
int second = list[j];
if (sum == first + second)
{
return new Tuple<int, int>(i, j);
}
}
}
return null;
}
Here's code that passes all 4 tests. There's abuncha issues about the problem, however, that make it interesting. Basic test: iterate through a list, for each number in the list, iterate through the list and find its pair, ie that which when added together equal the target value. So it's O(n**2) algorithm. The 4th test burns that down. A big hint here, you only have to return the first matching pair. So, to solve:
double iterate through the list and return solution
special case for null list
special case for no solution found
special case for entry which when doubled equals the target: they must have a different index. eg:({5,1,3}, 10) 5+5=10, however, there must be a second 5, so this fails, where ({5,1,3,5},10) succeeds returning (0,3)
So, to kick the algorithm down to O(n), we can keep a record of what #s we've found, because we only need to keep the 1st occurrence of each one. But, we need a flexible, fast, data structure to do it. Array fails because we don't know what size it will be at compile time. I tried List. So you have 10million ones, it saves the first list[0]=1, and charges on. Next is 2, 2+1!=10, add 2 to list, move on. Works.
until you have an input of 10million sequential ints, and the list is huge. So switch to Dictionary. Now it passes all 4 tests.
So, sequence through input list, for each item, search its pair in the dictionary. If not, search this item in dictionary, if not, add it. When you do find its pair in the dictionary, set your return and go.
public class Item
{
public Item(int _val, int _loc) {
val = _val;
loc = _loc;
}
public int val;
public int loc;
}
class TwoSum
{
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
Tuple<int, int> result = null;
Dictionary<int, Item> dictionary = new Dictionary<int, Item>();
int index = 0;
bool done = false;
do
{
int curr = list[index];
int pair = sum - list[index];
if (dictionary.ContainsKey(pair))
{
result = new Tuple<int, int>(index, dictionary[pair].loc);
done = true;
}
else
{
if (! dictionary.ContainsKey(curr))
{
Item found1 = new Item(curr, index);
dictionary.Add(curr, found1);
}
}
index++;
}
while (index < list.Count && !done);
return result;
}
A even simpler way is:
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
// subtract the item to the sum to find the difference
int diff = sum - list[i];
// if that number exist in that list find its index
if (list.Contains(diff))
{
return Tuple.Create(i, list.IndexOf(diff));
}
}
return null;
}
That way you wouldn't need to lookup the entire list in advance, it still is a 75% though.
int[] arr = new int[] { 1, 0, 2, 3, 4, 3 };
for (int i = 0; i < arr.Length; i++)
{
var requiredElements = arr.Select((item, index) => new { index, item }).Where(ind => ind.item.Equals(4 - arr[i])).ToList();
if (requiredElements.Count > 0)
{
foreach (var disp in requiredElements)
Console.WriteLine("Indexes are " + i.ToString() + ":" + disp.index);
}
break;
}
}
// Where 4 is the target into - ind.item.Equals(4 - arr[i])
Here is my solution. As far as I test, It returns right indices. But I don't know if it is efficient for performance.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
int difference = sum - list[i];
bool isExist = list.Contains(difference);
if (!isExist)
{
continue;
}
else if (difference == list[i] && list.Where(x => x == difference).ToList().Count > 1)
{
var duplicated = list.Select((item, index) => new { Value = item, Index = index }).Where(x => x.Value == difference).Take(2).ToList();
return new Tuple<int, int>(duplicated[0].Index, duplicated[1].Index);
}
else if (difference == list[i] && list.Where(x => x == difference).ToList().Count == 1) continue;
else
{
return new Tuple<int, int>(i, list.IndexOf(difference));
}
}
return null;
}
Edit:
My first solution has a huge performance problem. So I decided to improve Mohammed Turshan's solution. I think it has duplication bug. I solved that problem by using Dictionary class.
public static Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
Dictionary<int, int> dict = list.Select((value, index) =>
new { Value = value, Index = index }).ToDictionary(x => x.Index, x => x.Value);
var result = from n1 in dict
from n2 in dict
where n1.Value + n2.Value == sum && n1.Key != n2.Key
select new Tuple<int, int>(n1.Key, n2.Key);
return result.FirstOrDefault();
}
As far as I'm concerned, building a lookup table is just extra memory and overhead. In addition, it processes every item in the list rather than stopping when a match is found.
So why not just something like this?
public Tuple<int, int> FindTwoSum(IList<int> list, int sum)
{
for (int i = 0; i < list.Count; i++)
{
for (int j = i + 1; j < list.Count; j++)
{
if (list[i] + list[j] == sum)
return new Tuple<int, int>(list[i], list[j]);
}
}
return null;
}
Maybe someone needs Java Solution
class Solution {
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> numAndIndex = new HashMap<>();
for(int currentIndex=0; currentIndex<nums.length; currentIndex++){
int currentNumber=nums[currentIndex];
Integer expectedIndex=numAndIndex.get(target-currentNumber);
if(expectedIndex!=null){
return new int[]{expectedIndex, currentIndex};
}
numAndIndex.put(currentNumber, currentIndex);
}
return null;
}
}
public static Tuple FindTwoSum(IList list, int sum)
{
for(int i=0;i<list.Count;i++)
{
for(int j=0;j<list.Count;j++)
{
if((list[i]+list[j])==12)
{
return new Tuple<int, int>(i,j);
}
}
}
return null;
}
This will work
Is there a way to use a loop that takes the first 100 items in a big list, does something with them, then the next 100 etc but when it is nearing the end it automatically shortens the "100" step to the items remaining.
Currently I have to use two if loops:
for (int i = 0; i < listLength; i = i + 100)
{
if (i + 100 < listLength)
{
//Does its thing with a bigList.GetRange(i, 100)
}
else
{
//Does the same thing with bigList.GetRange(i, listLength - i)
}
}
Is there a better way of doing this? If not I will at least make the "thing" a function so the code does not have to be copied twice.
You can make use of LINQ Skip and Take and your code will be cleaner.
for (int i = 0; i < listLength; i=i+100)
{
var items = bigList.Skip(i).Take(100);
// Do something with 100 or remaining items
}
Note: If the items are less than 100 Take would give you the remaining ones.
I didn't like any of the answers listed, so I made my own extension:
public static class IEnumerableExtensions
{
public static IEnumerable<IEnumerable<T>> MakeGroupsOf<T>(this IEnumerable<T> source, int count)
{
var grouping = new List<T>();
foreach (var item in source)
{
grouping.Add(item);
if(grouping.Count == count)
{
yield return grouping;
grouping = new List<T>();
}
}
if (grouping.Count != 0)
{
yield return grouping;
}
}
}
Then you can use it:
foreach(var group in allItems.MakeGroupsOf(100))
{
// Do something
}
You can keep an explicit variable for the end point:
for (int i = 0, j; i < listLength; i = j)
{
j = Math.min(listLength, i + 100);
// do your thing with bigList.GetRange(i, j)
}
In dotnet 6 you can use chunk:
//Child collections will be comprised of 10 elements each.
IEnumerable<int[]> sublists = numbers.Chunk(10);
https://exceptionnotfound.net/bite-size-dotnet-6-chunk-in-linq/
There is also a reference to use a group by to do this, which is quite an interesting solution for older versions of the framework:
Split a collection into `n` parts with LINQ?
List<int> list = null;
int amount_of_hundreds = Math.Floor(list.Count/100);
int remaining_number = list.Count - (amount_of_hundreds * 100);
for(int i = 0; i < amount_of_hundreds; ++i)
{
for(int j = 0; j < 100; ++j)
{
int item = list[(i * 100) + j];
// do what you want with item
}
}
for(int i = 0; i < remaining_number; ++i)
{
int item = list[(amount_of_hundreds * 100) + i];
// do what you want with item
}
you can try below approach also:
int i = 1;
foreach (item x in bigList)
{
batchOperation.Insert(x); //replace it with your action; create the batch
i++;
if (i >100)
{
table.ExecuteBatch(batchOperation); //execute the batch
batchOperation.Clear();
i = 1; // re-initialize
}
}
if (batchOperation.Count >= 1 )
{
table.ExecuteBatch(batchOperation); //do this for the residue items
}
This is my solution, before all, i skip the last rows (rows - skiplast) after i get top of the array.
[TestMethod]
public void SkipTake()
{
var rows = 100;
var skip = 1;
var skiplast = 95;
var result = Enumerable.Range(1, rows).Take(rows - skiplast).Skip(skip - 1 == 0 ? 1 : skip).ToList();
}
You can split one big List to many small lists by limit, like this:
var limit = 100;
foreach (var smallList in bigList.Select((x, i) => new { Index = i, Value = x })
.GroupBy(x => x.Index / limit)
.Select(x => x.Select(v => v.Value).ToList())
.ToList())
{
Console.WriteLine($"{smallList.Count}");
Console.WriteLine(String.Join("\r\n", smallList));
}
How would I go about generating a list of all combinations of words up to a certain length from a List<string> source?
For example, I have a List<string> of 10,600+ words which I need to convert to a List<List<string>>, however, the sub list only needs to contain combinations up to and including a given maximum length, for this example, I'll say 3.
I don't care about the order in which the words appear in the sub list. For example, I only need 1 of the following in the list:
"laptop", "computer", "reviews"
"laptop", "reviews", "computer"
"computer", "laptop", "reviews"
"computer" "reviews", "laptop"
"reviews", "computer", "laptop"
"reviews", "laptop", "computer"
Is it even possible given the large number of combinations I would need to generate?
Any help is much appreciated.
First of all, I'm not sure that you really want to generate such huge list. If you really do, then I suggest you to consider to use iterators for lazy list generation instead of this huge list:
static void Main()
{
var words = new List<string> {"w1", "w2", "w3", "w4", "w5", "w6", "w7"};
foreach (var list in Generate(words, 3))
{
Console.WriteLine(string.Join(", ", list));
}
}
static IEnumerable<List<string>> Generate(List<string> words, int length, int ix = 0, int[] indexes = null)
{
indexes = indexes ?? Enumerable.Range(0, length).ToArray();
if (ix > 0)
yield return indexes.Take(ix).Select(x => words[x]).ToList();
if (ix > length)
yield break;
if (ix == length)
{
yield return indexes.Select(x => words[x]).ToList();
}
else
{
for (int jx = ix > 0 ? indexes[ix-1]+1 : 0; jx < words.Count; jx++)
{
indexes[ix] = jx;
foreach (var list in Generate(words, length, ix + 1, indexes))
yield return list;
}
}
}
Hopefully I didn't mess with anything.
for(int i = 0; i < list.Count; i ++)
{
list1 = new List<string> { list[i] };
listcombinations.Add(list1);
for(int j = i + 1; j < list.Count; j ++)
{
list1 = new List<string> { list[i], list[j] };
listcombinations.Add(list1);
for(int k = j + 1; k < list.Count; k ++)
{
list1 = new List<string> { list[i], list[j], list[k] };
listcombinations.Add(list1);
}
}
}
i suppose the problem is mostly to check if a combination of words exists already in the list:
what you can do for that:
//generate a dictionary with key hashcode / value list of string
Dictionary<int, List<string>> validCombinations= new Dictionary<int, List<string>>();
//generating anyway your combinations (looping through the words)
List<string> combinationToCheck = new List<string>(){"reviews", "laptop", "computer"};
//sort the words
combinationToCheck.Sort();
string combined = String.Join("", combinationToCheck.ToArray());
//calculate a hash
int hashCode = combined.GetHashCode();
//add the combination if the same hash doesnt exist yet
if(!validCombinations.ContainsKey(hashCode))
validCombinations.Add(hashCode, combinationToCheck);
private List<List<string>> GetCombinations()
{
List<List<string>> mResult= new List<List<string>>();
for (int i = 0; i < mList.Count; i++)
{
for (int k = 0; k < mList.Count; k++)
{
if (i == k) continue;
List<string> tmpList = new List<string>();
tmpList.Add(mList[i]);
int mCount = 1;
int j = k;
while (true)
{
if (j >= mList.Count) j = 0;
if (i != j)
{
tmpList.Add(mList[j]);
mCount++;
}
j += 1;
if (mCount >= mList.Count) break;
}
mResult.Add(tmpList);
}
}
return mResult;
}
I've read lots of posts about sorting a 2D array but I still can't master it so I was wondering if anyone can offer me some advice...
I have an aray which lists letters and quantity (I'm doing a frequency anaysis on a piece of text). I've read this data into a rectangle array and need to order it by highest frequency first. Here's my code so far:
//create 2D array to contain ascii code and quantities
int[,] letterFrequency = new int[26, 2];
//fill in 2D array with ascaii code and quantities
while (asciiNo <= 90)
{
while ((encryptedText.Length - 1) > counter)
{
if (asciiNo == (int)encryptedText[index])
{
letterCount++;
}
counter++;
index++;
}
letterFrequency[(storeCount), (0)] = (char)(storeCount+66);
letterFrequency[(storeCount), (1)] = letterCount;
storeCount++;
counter=0;
index=0;
letterCount = 0;
asciiNo++;
}
You are using a 2D array to represent 2 separate vectors - the symbols and the counts. Instead, use 2 separate arrays. Array.Sort has an overload that takes 2 arrays, and sorts on one array, but applies the changes to both, achieving what you want.
This would also allow you to use a char[] for the characters rather than int[]:
char[] symbols = ...
int[] counts = ...
...load the data...
Array.Sort(counts, symbols);
// all done!
At this
point, the counts have been ordered, and the symbols will still match index-by-index with the count they relate to.
You can wrap letter-count pair in a struct and use linq methods to manipulate data:
struct LetterCount {
public char Letter { get; set; }
public int Count { get; set; }
}
Sorting by count will look like this:
List<LetterCount> counts = new List<LetterCount>();
//filling the counts
counts = counts.OrderBy(lc => lc.Count).ToList();
public static void Sort2DArray<T>(T[,] matrix)
{
var numb = new T[matrix.GetLength(0) * matrix.GetLength(1)];
int i = 0;
foreach (var n in matrix)
{
numb[i] = n;
i++;
}
Array.Sort(numb);
int k = 0;
for (i = 0; i < matrix.GetLength(0); i++)
{
for (int j = 0; j < matrix.GetLength(1); j++)
{
matrix[i, j] = numb[k];
k++;
}
}
}
Alternative approach:
var counts = new Dictionary<char,int>();
foreach(char c in text) {
int count;
counts.TryGetValue(c, out count);
counts[c] = count + 1;
}
var sorted = counts.OrderByDescending(kvp => kvp.Value).ToArray();
foreach(var pair in sorted) {
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
(untested)
In this case I'd choose to make use of KeyValuePair<TKey, TValue> and instead use something like this:
//create 2D array to contain ascii code and quantities
KeyValuePair<char, int>[] letterFrequency = new KeyValuePair<char, int>[26];
//fill in 2D array with ascaii code and quantities
while (asciiNo <= 90)
{
while ((encryptedText.Length - 1) > counter)
{
if (asciiNo == (int)encryptedText[index])
{
letterCount++;
}
counter++;
index++;
}
letterFrequency[storeCount] = new KeyValuePair<char, int>((char)(storeCount+66), letterCount);
storeCount++;
counter=0;
index=0;
letterCount = 0;
asciiNo++;
}
Then use Array.Sort:
Array.Sort(letterFrequency, (i1, i2) => i2.Value.CompareTo(i1.Value));
This'll sort a two dimension array, the bool specifies if it's sorted on the second dimension, but default it sorts on the first dimension.
void SortDoubleDimension<T>(T[,] array, bool bySecond = false)
{
int length = array.GetLength(0);
T[] dim1 = new T[length];
T[] dim2 = new T[length];
for (int i = 0; i < length; i++)
{
dim1[i] = array[i, 0];
dim2[i] = array[i, 1];
}
if (bySecond) Array.Sort(dim2, dim1);
else Array.Sort(dim1, dim2);
for (int i = 0; i < length; i++)
{
array[i, 0] = dim1[i];
array[i, 1] = dim2[i];
}
}
Why are you storing the character? You can infer it from the array index and do not need to store it! Use a one-dimensional array instead.
string encryptedText = "Test".ToUpper();
int[] frequency = new int[26];
foreach (char ch in encryptedText) {
int charCode = ch - 'A';
frequency[charCode]++;
}
var query = frequency
.Select((count, index) => new { Letter = (char)(index + 'A'), Count = count })
.Where(f => f.Count != 0)
.OrderByDescending(f => f.Count)
.ThenBy(f => f.Letter);
foreach (var f in query) {
Console.WriteLine("Frequency of {0} is {1}", f.Letter, f.Count);
}