I have a situation where I need to sort arrays and preserve the current key - value pairs.
For example, this array:
(0) = 4
(1) = 3
(2) = 1
(3) = 2
Needs to sort like this
(2) = 1
(3) = 2
(1) = 3
(0) = 4
Retaining the original keys. Array.Sort(myArray) sorts into the right sequence but doesn't keep the indexes. I need a variant that does.
edit
Using the links, this seems close to what I want. Do I just need to remove the extra brackets to convert this to vb.net?
myList.Sort((firstPair,nextPair) =>
{
return firstPair.Value.CompareTo(nextPair.Value);
}
);
(also would I intergrate this as a function or something else?)
In an array, the order is determined by the indexes (what you call "keys"). Thus, there cannot be an array like this:
(2) = 1
(3) = 2
(1) = 3
(0) = 4
What you need is a data structure that has keys, values and an order (which is independent from the keys). You can use a List(Of KeyValuePair) or (if you use .net 4) List(Of Tuple(Of Integer, Integer)) for this; a few examples are shown in the link provided by Ken in the comment (which I will repeat here for convenience):
How do you sort a C# dictionary by value?
EDIT: Another option would be to use LINQ to automatically create a sorted IEnumerable(Of Tuple(Of Integer, Integer)):
Dim a() As Integer = {4, 3, 1, 2} ' This is your array
Dim tuples = a.Select(Function(value, key) New Tuple(Of Integer, Integer)(key, value))
Dim sorted = tuples.OrderBy(Function(t) t.Item2)
(untested, don't have Visual Studio available right now)
Since you are using .net 2.0 (since you said that you are using Visual Studio 2005 in one of the comments), using an OrderedDictionary might be an option for you, if every array value appears only once. Since OrderedDictionaries are ordered by the key, you could add your array entries to such a dictionary, using
the array index as the dictionary value and
the array value as the dictionary key (which will be used to order the dictionary).
What you are looking for is storing it as a Dictionary < int,int > and sort by the dictionary by Value.
I think the VB .Net synatx for dictionary is Dictionary( of Int, Int)
Related
im working on a project and i have a list in kotlin like:
val list = listOf("banana", "1","apple","3","banana","2")
and i want to print it like
Output:
banana = 1
banana = 2
apple = 3
so like every work with the number should be like one val, and i need to print in scific order (the order is toooo random for any sort command), so im panning on just coppying the whole xinhua dictionary here (since all chinese words have a scific unicode), and make the code it replace like:
val list = listOf("banana丨", "1","apple丩","3","banana丨","2")
but how to print them in the order?
ps. even me as a chinese dont know most of the words in xinhua dictionary lol so there is more then enofe
Assuming that you have the following input list, as shown in your question, where the order of occurrence is always one word followed by the scific order:
val list = listOf("banana", "1","apple","3","banana","2")
You could do the following:
1. Create a data class that defines one entry in your raw input list
data class WordEntry(val word: String, val order: Int)
2. Map over your raw input list by using the windowed and map methods
val dictionary = list.windowed(2, 2).map { WordEntry(it.first(), it.last().toInt()) }
Here, the windowed(2, 2) method creates a window of size 2 and step 2, meaning that we iterate over the raw input list and always work with two entries at every second step. Assuming that the order in the raw input list is always the word followed by the scific order, this should work. Otherwise, this would not work, so the order is very important here!
3. Sort the transformed dictionary by the order property
val sortedDictionary = dictionary.sortedBy { it.order }
Edit: You can also sort by any other property. Just pass another property to the lambda expression of sortedBy (e.g. sortedBy { it.word } if you want to sort it by the word property)
4. Finally, you can print out your sorted dictionary
val outputStr = sortedDictionary.joinToString("\n") { "${it.word} = ${it.order}" }
print(outputStr)
Output:
banana = 1
banana = 2
apple = 3
I am using some code that I found at AllenBrowne.com, which works fine, but I have a question about what it's doing.
The code is designed to return information about any index found on a specific column of a table in MS Access. Index types are identified with a constant, and there are four possible index types (including None):
Private Const intcIndexNone As Integer = 0
Private Const intcIndexGeneral As Integer = 1
Private Const intcIndexUnique As Integer = 3
Private Const intcIndexPrimary As Integer = 7
The relevant piece of code is as follows:
Private Function IndexOnField(tdf As DAO.TableDef, fld As DAO.Field) As Integer
'Purpose: Indicate if there is a single-field index on this field in this table.
'Return: The constant indicating the strongest type.
Dim ind As DAO.Index
Dim intReturn As Integer
intReturn = intcIndexNone
For Each ind In tdf.Indexes
If ind.Fields.Count = 1 Then
If ind.Fields(0).Name = fld.Name Then
If ind.Primary Then
intReturn = (intReturn Or intcIndexPrimary)
ElseIf ind.Unique Then
intReturn = (intReturn Or intcIndexUnique)
Else
intReturn = (intReturn Or intcIndexGeneral)
End If
End If
End If
Next
'Clean up
Set ind = Nothing
IndexOnField = intReturn
End Function
To be truthful, I didn't really understand the concept of a bitwise OR operator, so I've spent the last couple of hours researching that, so now I think I do. And along the way, I noticed that the four possible index values equate to a clear binary pattern:
None: 0
General: 1
Unique: 11
Primay: 111
All of which is good. But I don't understand the use in the function of the OR operator, in the lines:
If ind.Primary Then
intReturn = (intReturn Or intcIndexPrimary)
ElseIf ind.Unique Then
intReturn = (intReturn Or intcIndexUnique)
Else
intReturn = (intReturn Or intcIndexGeneral)
End If
Given that the structure of this code means that only one path can ever be returned, why not just return the actual required constant, without the use of OR? I know that Allen Browne's code is always well crafted, so he won't, I assume, have done this without good reason, but I can't see what it is.
Can someone help, so that I can better understand - and write better code myself in future?
Thanks
As basodre pointed to about the bitwise is correct, but not the 2, 4, 8 basis.
When dealing with an index, ALL of the possibilities are possible, hence the 1, 3, 7 (right-most 3 bits).
0000 = No index
0001 = regular index
0011 = unique index
0111 = PRIMARY index
So, the IF block is testing with the HIGHEST QUALIFIER of the type of index.
Any index can be regular, no problem.
some indexes can be unique, and they could be on some sort of concatenated fields to want as unique that have NOTHING to do with the primary key of the table
Last IS the primary key of the table - which is ALSO UNIQUE.
So, if the index you are testing against IS the primary, it would also show as true if you asked if it was an index or even if it was a unique index.
So, what it is doing is starting the
intReturn = intcIndexNone
which in essence sets the return value to a default of 0. Then it cycles through all indexes in the table that have the given field as part of an index. A table could have 20 indexes on it and 5 of them have an index using the field in question. That one field could be used as any possible part of a regular, unique or primary key index.
So the loop is starting with NONE (0). Then going through each time the field is found as associated with an index. Then whatever type of index that current index is, ORs the result.
So lets say that the index components as it goes through show a given field as Unique first, then regular, then Primary just for grins to see the result of the OR each cycle.
def intReturn 0000
OR Unique 0011
====
0011 NEW value moving forward
intReturn 0011
OR Regular 0001
====
0011 Since unique was higher classification, no change
intReturn 0011
OR Primary 0111
====
0111 Just upgraded to the highest classification index
So now, its returning the OR'd result of whatever the previous value was. In this case, the highest index association is "Primary" index
Does that clarify it for you?
The bitwise OR is useful in cases where combinations of values can exist, and you'd want to return an additive value. In this specific code block, the code is looping through each of the indices, and setting the flag based on the specific index. If there are two indexes, and one of them is general and the other is primary, you can encode this information in resultant bit pattern.
I'm confused by the choice of bitmaps, though. By choosing values with all of the bits set to true, you'd lose information about individual items (maybe that's a design element).
Generally, bitmaps might look something like:
Option A = 2 --> 0010
Option B = 4 --> 0100
Option C = 8 --> 1000
If you want both Option A and Option B to be true, the BIT OR would return 6, which is 0110.
Now, if you need to test if option A is true, you use the BIT AND operation. If you test (6 BIT AND 2) it will return a value greater than 0. However, if you test (8 BIT AND 6), which is the value for option c, it will return a 0.
Hopefully that adds some clarity. I don't have much information about how Access specifically works with indexes, so I'm just speaking to the general case.
EDIT: So I re-read the function definition, and it seems like the choice of integers is intentional. The function intentionally returns the strongest type of index. So, if there is a primary index, it will only show a primary. Considering this, I'm not sure that the bitwise or is the most self-descriptive option here. Maybe there is another consideration at play.
I have a dataframe which has a column called hexa which has hex values like this. They are of dtype object.
hexa
0 00802259AA8D6204
1 00802259AA7F4504
2 00802259AA8D5A04
I would like to remove the first and last bits and reverse the values bitwise as follows:
hexa-rev
0 628DAA592280
1 457FAA592280
2 5A8DAA592280
Please help
I'll show you the complete solution up here and then explain its parts below:
def reverse_bits(bits):
trimmed_bits = bits[2:-2]
list_of_bits = [i+j for i, j in zip(trimmed_bits[::2], trimmed_bits[1::2])]
reversed_bits = [list_of_bits[-i] for i in range(1,len(list_of_bits)+1)]
return ''.join(reversed_bits)
df['hexa-rev'] = df['hexa'].apply(lambda x: reverse_bits(x))
There are possibly a couple ways of doing it, but this way should solve your problem. The general strategy will be defining a function and then using the apply() method to apply it to all values in the column. It should look something like this:
df['hexa-rev'] = df['hexa'].apply(lambda x: reverse_bits(x))
Now we need to define the function we're going to apply to it. Breaking it down into its parts, we strip the first and last bit by indexing. Because of how negative indexes work, this will eliminate the first and last bit, regardless of the size. Your result is a list of characters that we will join together after processing.
def reverse_bits(bits):
trimmed_bits = bits[2:-2]
The second line iterates through the list of characters, matches the first and second character of each bit together, and then concatenates them into a single string representing the bit.
def reverse_bits(bits):
trimmed_bits = bits[2:-2]
list_of_bits = [i+j for i, j in zip(trimmed_bits[::2], trimmed_bits[1::2])]
The second to last line returns the list you just made in reverse order. Lastly, the function returns a single string of bits.
def reverse_bits(bits):
trimmed_bits = bits[2:-2]
list_of_bits = [i+j for i, j in zip(trimmed_bits[::2], trimmed_bits[1::2])]
reversed_bits = [list_of_bits[-i] for i in range(1,len(list_of_bits)+1)]
return ''.join(reversed_bits)
I explained it in reverse order, but you want to define this function that you want applied to your column, and then use the apply() function to make it happen.
In the following LINQ example, how can you get a list of index numbers from the original rows that the group is made up of? I would like to show the user where the data comes from.
Dim inputDt As New DataTable
inputDt.Columns.Add("Contractor")
inputDt.Columns.Add("Job_Type")
inputDt.Columns.Add("Cost")
inputDt.Rows.Add({"John Smith", "Roofing", "2408.68"})
inputDt.Rows.Add({"John Smith", "Electrical", "1123.08"})
inputDt.Rows.Add({"John Smith", "Framing", "900.99"})
inputDt.Rows.Add({"John Smith", "Electrical", "892.00"})
Dim results = From rows In inputDt Where rows!Contractor <> ""
Group rows By rows!Job_Type
Into cost_total = Sum(CDec(rows!Cost))
For Each r In results
' Show results.
'r.Job_Type
'r.cost_total
' Show line numbers of original rows... ?
Next
For the result (Job_Type="Electrical", cost_total=2015.08), the original index numbers are 1 and 3.
Thanks
First and perhaps foremost, set Option Strict On. This will not allow the old VB6 style rows!Cost type notation. But this is for the better because that way always returns Object and the data rarely is. This is no loss at all as NET has better ways to type and convert variables.
Second, and somewhat related, is that all your DataTable columns are text even though one is clearly decimal. Next, your query relates to working with the data in the table but you want to also include a DataRow property which is a bit odd. Better would be to add an Id or Number to the data to act as the identifier. This will also help the results make sense if the View (order of rows) changes.
You did not clarify whether you wanted a CSV of indices (now IDs) or a collection of them. A CSV of them seems simpler, so thats what this does.
The code also uses more idiomatic names and demonstrates casting data to the needed type using other extension methods. It also uses the extension method approach. First the DataTable with non-string Data Types specified:
Dim inputDt As New DataTable
inputDt.Columns.Add("ID", GetType(Int32))
inputDt.Columns.Add("Contractor")
inputDt.Columns.Add("JobType")
inputDt.Columns.Add("Cost", GetType(Decimal))
inputDt.Rows.Add({1, "John Smith", "Roofing", "2408.68"})
inputDt.Rows.Add({5, "John Smith", "Electrical", "1123.08"})
inputDt.Rows.Add({9, "John Smith", "Framing", "900.99"})
inputDt.Rows.Add({17, "John Smith", "Electrical", "892.00"})
then the query:
Dim summary = inputDt.AsEnumerable().GroupBy(Function(g) g.Field(Of String)("JobType"),
Function(k, v) New With {.Job = k,
.Cost = v.Sum(Function(q) q.Field(Of Decimal)("Cost")),
.Indices = String.Join(",", inputDt.AsEnumerable().
Where(Function(q) q.Field(Of String)("JobType") = k).
Select(Function(j) j.Field(Of Int32)("Id")))
}).
OrderBy(Function(j) j.Cost).
ToArray()
' Debug, test:
For Each item In summary
Console.WriteLine("Job: {0}, Cost: {1}, Ids: {2}", item.Job, item.Cost, item.Indices)
Next
The excessive scroll is unfortunate but I left it to allow the clauses to align with what "level" they are acting at. As you can see, a separate query is run on the DataTable to get the matching Indicies.
It is a little more typical to write such a thing as
Dim foo = Something.GroupBy(...).Select(...)
But you can skip the SELECT by using this overload of GroupBy as the above does:
Dim foo = Something.GroupBy(Function (g) ..., Function (k, v) ... )
Results:
Job: Framing, Cost: 900.99, Ids: 9
Job: Electrical, Cost: 2015.08, Ids: 5,17
Job: Roofing, Cost: 2408.68, Ids: 1
How to sort somelist As List(of T) by the order set in another list sortorder As List(of Integer)? Both somelist and sortorder are of the same size and are indexed from 0 to n. Integers in the sortorder list determine the sort order: new index of item X in somelist = value of item X in sortorder.
Like this:
somelist = (itemA, itemB, itemC)
sortorder = (3, 1, 2)
somelist.sort()
somelist = (itemB, itemC, itemA)
I am trying to sort several equally sized lists using the predefined sort order.
You could use LINQ, although i hate the ugly method syntax in VB.NET:
somelist = somelist.
Select(Function(t, index) New With {.Obj = t, .Index = index}).
OrderBy(Function(x) sortorder(x.Index)).
Select(Function(x) x.Obj).
ToList()
This uses the overload of Enumerable.Select that projects the index of the item. The object and the index are stored in an anonymous type which is used for the ordering, finally i'm selecting the object and use ToList to build the ordered list.
Another way is to use Enumerable.Zip to merge both into an anonymous type:
Dim q = From x In somelist.Zip(sortorder, Function(t, sort) New With {.Obj = t, .Sort = sort})
Order By x.Sort Ascending
Select x.Obj
somelist = q.ToList()
If you want to order it descending, so the highest values first, use OrderByDescending in the method syntax and Order By x.Sort Descending in the query.
But why do you store such related informations in two different collections at all?