I have a list of integer values which can be anywhere between 1 and 4.
So, let's say {1,2,4,1,3,2,1,4,4} for instance.
I now want to reverse the values in the following way:
All entries with ...
1 should be converted to 4,
2 should be converted to 3,
3 should be converted to 2,
4 should be converted to 1.
There are numerous ways to do this but I want to take the most efficient approach.
Any thoughts?
for(int i = 0; i < array.Length; i++)
{
array[i] = 5 - array[i];
}
Implement this function:
f(x) = 5 - x
The most efficient will be a for loop with a case statement but it won't be the most flexible or pretty to look at. Any solution you can come up this that only iterates the loop one time could be considered decent solutions since they will all be O(N) performing.
Try the following:
var result = list.Select(item => 5 - item);
I don't know about efficiency, but I'm thinking that first filtering out all duplicates (think there's a LINQ-extension-method for that), then sorting from smallest to biggest, and last creating a hash-map (Dictionary<int, int>) that holds the conversions. Then you can run trough the array like this:
for(int i = 0, l = sortedUniqueArray.Count; i < l; i++) {
dict[sortedUniqueArray[i]] = sortedUniqueArray[l - i];
}
Or something like that. Then you can do the final replacement like this:
orgArray.Select(itm => dict[itm]);
I think good way to write rules of convert and using this rules perform converting.
Related
I am new to C#. The following code was a solution I came up to solve a challenge. I am unsure how to do this without using List since my understanding is that you can't push to an array in C# since they are of fixed size.
Is my understanding of what I said so far correct?
Is there a way to do this that doesn't involve creating a new array every time I need to add to an array? If there is no other way, how would I create a new array when the size of the array is unknown before my loop begins?
Return a sorted array of all non-negative numbers less than the given n which are divisible both by 3 and 4. For n = 30, the output should be
threeAndFour(n) = [0, 12, 24].
int[] threeAndFour(int n) {
List<int> l = new List<int>(){ 0 };
for (int i = 12; i < n; ++i)
if (i % 12 == 0)
l.Add(i);
return l.ToArray();
}
EDIT: I have since refactored this code to be..
int[] threeAndFour(int n) {
List<int> l = new List<int>(){ 0 };
for (int i = 12; i < n; i += 12)
l.Add(i);
return l.ToArray();
}
A. Lists is OK
If you want to use a for to find out the numbers, then List is the appropriate data structure for collecting the numbers as you discover them.
B. Use more maths
static int[] threeAndFour(int n) {
var a = new int[(n / 12) + 1];
for (int i = 12; i < n; i += 12) a[i/12] = i;
return a;
}
C. Generator pattern with IEnumerable<int>
I know that this doesn't return an array, but it does avoid a list.
static IEnumerable<int> threeAndFour(int n) {
yield return 0;
for (int i = 12; i < n; i += 12)
yield return i;
}
D. Twist and turn to avoid a list
The code could for twice. First to figure the size or the array, and then to fill it.
int[] threeAndFour(int n) {
// Version: A list is really undesirable, arrays are great.
int size = 1;
for (int i = 12; i < n; i += 12)
size++;
var a = new int[size];
a[0] = 0;
int counter = 1;
for (int i = 12; i < n; i += 12) a[counter++] = i;
}
if (i % 12 == 0)
So you have figured out that the numbers which divides both 3 and 4 are precisely those numbers that divides 12.
Can you figure out how many such numbers there are below a given n? - Can you do so without counting the numbers - if so there is no need for a dynamically growing container, you can just initialize the container to the correct size.
Once you have your array just keep track of the next index to fill.
You could use Linq and Enumerable.Range method for the purpose. For example,
int[] threeAndFour(int n)
{
return Enumerable.Range(0,n).Where(x=>x%12==0).ToArray();
}
Enumerable.Range generates a sequence of integral numbers within a specified range, which is then filtered on the condition (x%12==0) to retrieve the desired result.
Since you know this goes in steps of 12 and you know how many there are before you start, you can do:
Enumerable.Range(0,n/12+1).Select(x => x*12).ToArray();
I am unsure how to do this without using List since my understanding is that you can't push to an array in C# since they are of fixed size.
It is correct that arrays can not grow. List were invented as a wrapper around a array that automagically grows whenever needed. Note that you can give List a integer via the Constructor, wich will tell it the minimum size it should expect. It will allocate at least that much the first time. This can limit growth related overhead.
And dictionaries are just a variation of the list mechanics, with Hash Table key search speed.
There is only 1 other Collection I know of that can grow. However it is rarely mentioned outside of theory and some very specific cases:
Linked Lists. The linked list has a unbeatable growth performance and the lowest issue of running into OutOfMemory Exceptions due to Fragmentation. Unfortunately, their random access times are the worst as a result. Unless you can process those collections exclusively sequentally from the start (or sometimes the end), their performance will be abysmal. Only stacks and queues are likely to use them. There is however still a implementation you could use in .NET: https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.linkedlist-1
Your code holds some potential too:
for (int i = 12; i < n; ++i)
if (i % 12 == 0)
l.Add(i);
It would way more effective to count up by 12 every itteration - you are only interested in every 12th number after all. You may have to change the loop, but I think a do...while would do. Also the array/minimum List size is easily predicted: Just divide n by 12 and add 1. But I asume that is mostly mock-up code and it is not actually that deterministic.
List generally works pretty well, as I understand your question you have challenged yourself to solve a problem without using the List class. An array (or List) uses a contiguous block of memory to store elements. Arrays are of fixed size. List will dynamically expand to accept new elements but still keeps everything in a single block of memory.
You can use a linked list https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.linkedlist-1?view=netframework-4.8 to produce a simulation of an array. A linked list allocates additional memory for each element (node) that is used to point to the next (and possibly the previous). This allows you to add elements without large block allocations, but you pay a space cost (increased use of memory) for each element added. The other problem with linked lists are you can't quickly access random elements. To get to element 5, you have to go through elements 0 through 4. There's a reason arrays and array like structures are favored for many tasks, but it's always interesting to try to do common things in a different way.
I was wondering if anyone could tell me about the i++ operator in C#.
I know it adds one to the int value, but I wouldn't have a clue where to use it, and if its only for loop statements, or can be used in general projects.
If I could get some practical examples of where you might use the i++ operator, thank you.
This is post-increment,which means that the increment will be done after the execution of the statement
int i=0;
Console.Write(i++); // still 0
Console.Write(i); // prints 1, it is incremented
In general, given this declaration:
var myNum = 0;
anywhere you would normally do this:
myNum += 1;
You could just do this:
myNum++;
What you are referring to is the C# post increment operator, common use case are :
Incrementing the counter variable in a standard for loop
Incrementing the counter variable in a while loop
Accessing an array in sequential order (3)
Example (3) :
int[] table = { 0, 1, 2, 3, 4, 5, 6 };
int i = 0;
int j = table[i++]; //Access the table array element 0
int k = table[i++]; //Access the table array element 1
int l = table[i++]; //Access the table array element 2
So, whats the post increment operator really does ?
It return the value of the variable and then increment it's value by 1 unit .
The expression i++ is just like x == y > 0 ? x : z which both are syntactic sugar.
x = i++ saves you the space of writing x=i; i=i+1;
Is it good or bad? There is really no exact answer to this.
I personally avoid these expressions as they make my code look complex, sometimes hard to debug. Always think code readability instead of write-ability, always think how your code looks readable instead of how easy is it to write it
I have a rather specific question about how to exclude items of one list from another. Common approaches such as Except() won't do and here is why:
If the duplicate within a list has an "even" index - I need to remove THIS element and the NEXT element AFTER it.
if the duplicate within a list had an "odd" index - I need to remove THIS element AND one element BEFORE** it.
there might be many appearances of the same duplicate within a list. i.e. one might be with an "odd" index, another - "even".
I'm not asking for a solution since I've created one myself. However after performing this method many times - "ANTS performance profiler" shows that the method elapses 75% of whole execution time (30 seconds out of 40). The question is: Is there a faster method to perform the same operation? I've tried to optimize my current code but it still lacks performance. Here it is:
private void removedoubles(List<int> exclude, List<int> listcopy)
{
for (int j = 0; j < exclude.Count(); j++)
{
for (int i = 0; i < listcopy.Count(); i++)
{
if (listcopy[i] == exclude[j])
{
if (i % 2 == 0) // even
{
//listcopy.RemoveRange(i, i + 1);
listcopy.RemoveAt(i);
listcopy.RemoveAt(i);
i = i - 1;
}
else //odd
{
//listcopy.RemoveRange(i - 1, i);
listcopy.RemoveAt(i - 1);
listcopy.RemoveAt(i - 1);
i = i - 2;
}
}
}
}
}
where:
exclude - list that contains Duplicates only. This list might contain up to 30 elements.
listcopy - list that should be checked for duplicates. If duplicate from "exclude" is found -> perform removing operation. This list might contain up to 2000 elements.
I think that the LINQ might be some help but I don't understand its syntax well.
A faster way (O(n)) would be to do the following:
go through the exclude list and make it into a HashSet (O(n))
in the checks, check if the element being tested is in the set (again O(n)), since test for presence in a HashSet is O(1).
Maybe you can even change your algorithms so that the exclude collection will be a HashSet from the very beginning, this way you can omit step 1 and gain even more speed.
(Your current way is O(n^2).)
Edit:
Another idea is the following: you are perhaps creating a copy of some list and make this method modify it? (Guess based on the parameter name.) Then, you can change it to the following: you pass the original array to the method, and make the method allocate new array and return it (your method signature should be than something like private List<int> getWithoutDoubles(HashSet<int> exclude, List<int> original)).
Edit:
It could be even faster if you would reorganize the input data in the following way: As the items are always removed in pairs (even index + the following odd index), you should pair them in advance! So that your list if ints becomes list of pairs of ints. This way your method might be be something like that:
private List<Tuple<int, int>> getWithoutDoubles(
HashSet<int> exclude, List<Tuple<int, int>> original)
{
return original.Where(xy => (!exclude.Contains(xy.Item1) &&
!exclude.Contains(xy.Item2)))
.ToList();
}
(you remove the pairs where either the first or the second item is in the exclude collection). Instead of Tuple, perhaps you can pack the items into your custom type.
Here is yet another way to get the results.
var a = new List<int> {1, 2, 3, 4, 5};
var b = new List<int> {1, 2, 3};
var c = (from i in a let found = b.Any(j => j == i) where !found select i).ToList();
c will contain 4,5
Reverse your loops so they start at .Count - 1 and go to 0, so you don't have to change i in one of the cases and Count is only evaluated once per collection.
Can you convert the List to LinkedList and have a try? The List.RemoveAt() is more expensive than LinkedList.Remove().
John Skeets answer to this question, Select all unique combinations of a single list, with no repeats, using LINQ, works awesomely.
However, can someone break down component by component the inner workings of how the first answer is working:
List<int> slotIds = new List<int> {1, 2, 3};
var query = slotIds.SelectMany((value, index) => slotIds.Skip(index + 1),
(first, second) => new { first, second });
It's roughly equivalent in concept to this, although the actual execution model is different of course (lazy etc):
for (int i = 0; i < slotIds.Count; i++)
{
int first = slotIds[i];
for (int j = i + 1; j < slotIds.Count; j++)
{
int second = slotIds[j];
results.Add(new { first, second });
}
}
The SelectMany taking a projection from value and index is a way of using both first and i to make an inner loop. We need the index so that we can skip index + 1 values, which is equivalent to the j loop starting at i + 1 in the above code.
Does that help? If not, could you pinpoint which bit is confusing?
EDIT: Aargh - I hadn't realized that the other question you were referring to started out with this code! I think it's still useful though, to give the paragraph below something to hang on...
If you understood the alternative (query expression) version of my answer, then the first version is similar, just using an overload of SelectMany which allows you to use both the value and index in the "outer" sequence.
I'm searching the way(s) to fill an array with numbers from 0 to a random. For example, from 0 to 12 or 1999, etc.
Of course, there is a for-loop:
var arr = int[n];
for(int i = 0; i < n; i++)
{
arr[i] = i;
}
And I can make this method been an extension for Array class. But is there some more interesting ways?
This already exists(returns IEnumerable, but that is easy enough to change if you need):
arr = Enumerable.Range(0, n);
The most interesting way in my mind produces not an array, but an IEnumerable<int> that enumerates the same number - it has the benefit of O(1) setup time since it defers the actual loop's execution:
public IEnumerable<int> GetNumbers(int max) {
for (int i = 0; i < max; i++)
yield return i;
}
This loop goes through all numbers from 0 to max-1, returning them one at a time - but it only goes through the loop when you actually need it.
You can also use this as GetNumbers(max).ToArray() to get a 'normal' array.
The best answer depends on why you need the array. The thing is, the value of any array element is equal to the index, so accessing any element is essentially a redundant operation. Why not use a class with an indexer, that just returnes the value of the index? It would be indistinguishable from a real array and would scale to any size, except it would take no memory and no time to set up. But I get the feeling it's not speed and compactness you are after. Maybe if you expand on the problem, then a better solution will be more obvious.