Say there's a list. Each item in the list has a unique id.
List [5, 2, 4, 3, 1]
When I remove an item from this list, the unique id from the item goes with it.
List [5, 2, 3, 1]
Now say I want to add another item to the list, and give it the least lowest unique id.
What's the easiest way to get the lowest unique id when adding a new item to the list?
Here's the restriction though: I'd prefer it if I didn't reassign the unique id of another item when deleting an item.
I realise it would be easy to find the unique id if I reassigned unique id 5 to unique id 4 when I deleted 4. Then I could get the length of the list (5) and creating the new item with the unique id with that number.
So is there another way, that doesn't involve iterating through the entire list?
EDIT:
Language is java, but I suppose I'm looking for a generic algorithm.
An easy fast way is to just put your deleted ids in a priority queue, and just pick the next id from there when you insert new ones (or use size() + 1 of the first list as id when the queue is empty). This would however require another list.
You could maintain a list of available ID's.
Declare a boolean array (pseudo code):
boolean register[3];
register[0] = false;
register[1] = false;
register[2] = false;
When you add an element, loop from the bottom of the register until a false value is found. Set the false value to true, assign that index as the unique identifier.
removeObject(index)
{
register[index] = false;
}
getsetLowestIndex()
{
for(i=0; i<register.size;i++)
{
if(register[i]==false)
{
register[i] = true;
return i;
}
}
// Array is full, increment register size
register.size = register.size + 1;
register[register.size] = true;
return register.size;
}
When you remove an element, simply set the index to false.
You can optimise this for larger lists by having continuality markers so you don't need to loop the entire thing.
This would work best for your example where the indexes are in no particular order, so you skip the need to sort them first.
Its equivalent to a search, just this time you search for a missing number. If your ID's are sorted integers, you can start going from bottom to top checking if the space between two ID's is 1.
If you know how many items in the list and its sorted you can implement a binary search.
I don't think you can do this without iterating through the list.
When you say
'Now say I want to add another item to
the list, and give it the least
highest unique id. '
I assume you mean you want to assign the lowest available ID that has not been used elsewhere.
You can do this:
private int GetLowestFreeID(List list){
for (int idx = 0; idx < list.Length; ++i){
if ( list[idx] == idx ) continue;
else return idx;
}
}
this returns the lowest free index.
This assumes your list is sorted, and is in C# but you get the idea.
The data structure that would be used to do this is a Priority Binary Heap that only allow unique values.
How about keeping the list sorted. and than you can remove it from one end easily.
Related
I'm extremely new to Apps Script and trying to make my first thing. It's a shopping list.
I want to create a function that will activate and then sort (by Column 1, 'Aisle #') all rows where there are values in a given other column (Column 3, 'Qty'). The idea is to sort the items on the list for that week (i.e., with a value filled in for Qty) by aisle to give me the order I should be looking for things. I do not want to sort items which are in the spreadsheet but without
a value for Qty.
Here is what I've got so far:
var sheet = ss.getActiveSheet()
var range = sheet.getDataRange();
var rangeVals = range.getValues()
function orderList2(){
if(rangeVals[3] != ""){
sheet.activate().sort(1, ascending=true);
};
};
I'm trying to use "if" to define which rows to activate before doing the sort (as I don't want to sort the entire sheet—I only want to sort the items I will be buying that week, i.e., the items with a value in Column 3). The script runs but ends up sorting the entire sheet.
The closest thing I could find was an iteration, but when I did it, it ended up only activating the top-left cell.
Any help you can provide would be greatly appreciated!
Cheers,
Nick
Answer:
Use Range.sort() instead of Sheet.sort() if you don't want to sort the entire sheet.
Explanation:
You want to sort the data according to the value in column A (Aisle #), if the corresponding value in C (Qty) is not empty.
If my assumption is correct, the rows where Qty is empty should go below the rest of data, and they should not be sorted according to their Aisle #.
In this case, I'd suggest the following:
Sort the full range of data (headers excluded) according to Qty, so that the rows without a Qty are placed at the bottom, using Range.sort() (if you don't need to exclude the headers, you can use Sheet.sort() instead).
Use SpreadsheetApp.flush() to apply the sort to the spreadsheet.
Use getValues(), filter() and length to know how many rows in the initial range have their column C populated (variable QtyElements in the sample below).
Using QtyElements, retrieve the range of rows with a non-empty column C, and sort it according to column 1, using Range.sort().
Code sample:
function orderList2() {
var sheet = SpreadsheetApp.getActiveSheet();
var firstRow = 2; // Range starts at row 2, header row excluded
var fullRange = sheet.getRange(firstRow, 1, sheet.getLastRow() - firstRow + 1, sheet.getLastColumn());
fullRange.sort(3); // Sort full range according to Qty
SpreadsheetApp.flush(); // Refresh spreadsheet
var QtyElements = fullRange.getValues().filter(row => row[2] !== "").length;
sheet.getRange(firstRow, 1, QtyElements, sheet.getLastColumn())
.sort(1); // If not specified, default ascending: true
//.sort({column: 1, ascending: false}); // Uncomment if you want descending sort
}
Reference:
Range.sort(sortSpecObj)
I am currently experiencing some issues regarding table view sorting from firebase. What I am trying to achieve is to list 5 different price tiers in a table view, all named (tier1, tier5, tier12, tier24, tierPermanent) - each containing a value (the price).
However, while fetching these values from the database, I find it rather difficult to show these in a table view - both containing text (the time) and the price tiers. What I am doing now, is that I am using observeEventType to display all the values, and then store each value in a dictionary. After that I append it to an array of dictionaries of type [[String:String]].
What I am struggling with, is to display this in a descending order in a table view. Please take note that all of these 5 values are optional, and therefore they might not contain any value - so instead of showing a value on the very first row, and a blank cell at the second, and then a new value on the third row - I want it to display descending compared to the values. (The permanent value will always be on top if it contains a value, or else tier24 will be on top, or else tier12.). For each cell.
I know I would access the unique value with cell.nameLabel.text = cell[indexPath.row]["tier.."] as? String - but the problem is that I need to have some sort of ordering, and make sure the data isn't displayed twice. (order with both key and value - to display both key and value in the same cell.).
Any ideas on how I would approach this?
Thanks in advance.
There's really not enough data to fully address the question but how about this:
A Firebase structure:
tiers
-Y0998uas9j
tier_type: tier_24
time: 20160705130100
sort_order: 1
-Ykja9s9js9
tier_type: tier_05
time: 20160705130300
sort_order: 3
-Yukl9jh8sj
tier_type: tier_permanent
time: 20160705130500
sort_order: 0
tiers have a sort order to keep them in the correct order.
tier_permanent = 0
tier_24 = 1
tier_12 = 2
tier_05 = 3
tier_01 = 4
and some code to read them in and keep the sorted, descending:
var myArray = [[String:String]]()
let tiersRef = self.myRootRef.child("tiers")
tiersRef.observeSingleEventOfType(.Value, withBlock: { snapshot in
for child in snapshot.children {
var dict = [String: String]()
dict["fbKey"] = child.key as String
dict["tier_type"] = child.value["tier_type"] as? String
dict["timestam"] = child.value["time"] as? String
dict["sort_order"] = child.value["sort_order"] as? String
myArray.append(dict)
}
myArray.sortInPlace( {$0["sort_order"] < $1["sort_order"]} )
self.mySuperTableView.reloadData()
for dict in myArray { //meh, print them so show they are sorted
print(dict)
}
})
This addresses: keeping them sorted, descending, and if the tires are not present in the database, they will obviously not be read in.
The issue is though, it's unclear from he question the correlation between the tier names and the value (time?). I'll update once more information has been presented.
I'm doing a project with Algorithm X (Dancing Links) and I'd like to know if the pseudocode for the column covering is correct. I've not found many pseudocodes that deal with "next Row" and "next Column" like Knuth's paper explains, so I haven't really been able to compare the rest to mine. But his paper is obviously not big on implementation details so I can't fully compare to it either.
I have something wrong in my Dancing Links code when I want to return multiple solutions (3888 for a 2x2 empty board, and it crashes with bigger boards) and everything is ""correct"" from the code's point of view, so I'm thinking maybe something about the concept is wrong.
This is the pseudocode (I know it looks like a lot but that's because I split it into 4 parts to minimize mistakes and making it easier to read, it's actually really really simple):
node::cover()
/*Does the unlinking/relinking of the Cover procedures*/
{
if this is the only visible node in the column
null its header's firstRow and lastRow pointers
else
this->previousRow sets its nextRow to this->nextRow
this->nextRow sets its previousRow to this->previousRow
if this is the first row of this->header
set this->header's first row as this->nextRow
else if this is the last row of this->header
set this->header's last row as this->previousRow
decrease this->header's amount of rows by 1
}
node::uncover()
/*Does the unlinking/relinking of the Uncover procedures*/
{
if this is the only visible node in the column
set its header's firstRow and lastRow pointers to this
else
this->previousRow sets its nextRow to this
this->nextRow sets its previousRow to this
if this->nextRow is the first row of this->header
set this->header's first row as this
else if this->previousRow is the last row of this->header
set this->header's last row as this
increase this->header's amount of rows by 1
}
node::coverRow(header H)
/*Covers the entire row.*/
{
index = this->nextNode
while index->header is different from H
index->cover()
index->nextNode
}
node::uncoverRow(header H)
/*Uncovers the entire row.*/
{
index = this->previousNode
while index->header is different from H
index->uncover()
index->previousNode
}
header::cover()
/*Covers column and calls to coverRow for each row*/
{
Set this->previousColumn as this->nextColumn
Set this->nextColumn as this->previousColumn
index = this->firstRow
if my index is not null
while index is different from lastRow
index->coverRow(this)
index = next row
lastRow->coverRow(this)
}
header::uncover()
/*Uncovers column and calls to coverRow for each row*/
{
Set previousColumn->nextColumn as this
Set nextColumn->previousColumn as this
index = this->lastRow
if my index is not null
while index is different from firstRow
index->uncoverRow(this)
index = previous row
firstRow->uncoverRow(this)
}
coverColumns(node selectedRow)
/*Gets a list of the headers (from the first node to the next node of the row) and goes through them, first to last, covering them.*/
{
get a list of the headers that are linked to that selectedRow
index = first node of the list
while index != end of the list
index->header->cover()
index = next node of the list
}
uncoverColumns(node selectedRow)
/*Gets a list of the headers (from the first node to the next node of the row) and goes through them, last to first, covering them.*/
{
get a list of the headers that are linked to that selectedRow
index = last node of the list
while index != beginning of the list
index->header->cover()
index = previous node of the list
}
The first thing you have is the selectedRow, and you have to call uncoverColumns with that as a parameter. From there I think (though, right now considering it's not working I'm not so sure) you have to get all the columns that are satisfied by that row. Once you have the three of them, you cover all their rows.
I hope the pseudocode is readable, it's the first time I've written pseudocode for someone else.
Thanks a lot in advance.
You need to do the operations in uncover in the opposite order than in cover. Currently you do them in the same order.
I have a string list (List) that contains delimited fields. An example would be:
List[0] = "7/1/2013,ABC,123456"
List[1] = "7/2/2013,DEF,234567"
I also have a DataTable where a record either will or will not contain the the values from the 2nd and 3rd column in the String List:
Example
Row[0][0]="ABC" <-----String
Row[0][1]=123456 <-----Int32
What I want to do is find any records (via Linq) in the DataTable that DO NOT have corresponding values in the String List.
I've been googling for a while, and can't quite find the right way to do this with Linq...can anyone help?
This code snippet should give you an enumeration of the indices that do not have the appropriate DataTable values:
var correspondingRecords =
from index in Enumerable.Range(0, List.Count)
let items = List[index].Split(',')
where !(item[1] == Row[index][0] && item[2] == Row[index][1])
select index;
The basic idea is to iterate over the indices in order to make sure that you're comparing the appropriate rows and list items to one another. Once you do that, it's simple enough to parse the list item and make the appropriate comparisons.
I have a datagrid. I add a row to the datagrid using an ADD button. Once I add, I sort the datagrid based on a column. I also provide the serial numbers i.e. row numbers as first column to the datagrid. But, the serial number function does not apply after sorting. Hence, a new row added for e.g. row 5, based on sorting should be row 1, the serial number displayed is still row 5. The UI looks bad as numbers are not in correct order. the code is :
// Sorting Function :
private function sortGrid():void
{
sortGridColl = new ArrayCollection(sortGridArray);
sortA = new Sort();
sortByLevel = new SortField("Type", true, false);
sortA.fields=[sortByLevel];
sortGridColl.sort=sortA;
sortGridColl.refresh();
sortGrid.dataProvider=sortGridColl;
sortGrid.rowCount=myDPColl.length +1;
}
// Serial Number function :
private function sortGridSerialNumbers(oItem:Object,iCol:int):String
{
myDPColl = new ArrayCollection(sortGridArray);
var iIndex:int = myDPColl.getItemIndex(oItem) + 1;
return String(iIndex);
}
// Adding new row to datagrid :
sortGrid.dataProvider.addItem
(
{
Type : typeName.text
}
);
Is sortGridSerialNumbers supposed to return the current serial numbers after sorting? Because it seems to only display the serial numbers for your original state. It won't give the correct value for any item that was added since you added the item to the dataProvider, not the original array.
I like arrays better than array collections, so my choice would be to maintain the list as a raw array. Then on each add, push the new element, do a sortOn (myArray.sortOn("Type")), then iterate over all items to adjust the serial number. Then apply the array to the datagrid as a new dataprovider.