Update: I can't get "Balancing" to work, because I cannot get "doAVLBalance" to recognize the member functions "isBalanced()", "isRightHeavy()", "isLeftHeavy". And I don't know why! I tried Sash's example(3rd answer) exactly but I get "deceleration is incompatible" and I couldn't fix that...so I tried doing it my way...and it tells me those member functions don't exist, when they clearly do.
"Error: class "IntBinaryTree:TreeNode" has no member "isRightHeavy".
I'm stuck after trying for the last 4 hours :(. Updated code below, help would be much appreciated!!
I'm creating a String based Binary Search Tree and need to make it a "Balanced" tree. How do I do this?* Help please!! Thanks in advance!
BinarySearchTree.cpp:
bool IntBinaryTree::leftRotation(TreeNode *root)
{
//TreeNode *nodePtr = root; // Can use nodePtr instead of root, better?
// root, nodePtr, this->?
if(NULL == root)
{return NULL;}
TreeNode *rightOfTheRoot = root->right;
root->right = rightOfTheRoot->left;
rightOfTheRoot->left = root;
return rightOfTheRoot;
}
bool IntBinaryTree::rightRotation(TreeNode *root)
{
if(NULL == root)
{return NULL;}
TreeNode *leftOfTheRoot = root->left;
root->left = leftOfTheRoot->right;
leftOfTheRoot->right = root;
return leftOfTheRoot;
}
bool IntBinaryTree::doAVLBalance(TreeNode *root)
{
if(NULL==root)
{return NULL;}
else if(root->isBalanced()) // Don't have "isBalanced"
{return root;}
root->left = doAVLBalance(root->left);
root->right = doAVLBalance(root->right);
getDepth(root); //Don't have this function yet
if(root->isRightHeavy()) // Don't have "isRightHeavey"
{
if(root->right->isLeftheavey())
{
root->right = rightRotation(root->right);
}
root = leftRotation(root);
}
else if(root->isLeftheavey()) // Don't have "isLeftHeavey"
{
if(root->left->isRightHeavey())
{
root->left = leftRotation(root->left);
}
root = rightRotation(root);
}
return root;
}
void IntBinaryTree::insert(TreeNode *&nodePtr, TreeNode *&newNode)
{
if(nodePtr == NULL)
nodePtr = newNode; //Insert node
else if(newNode->value < nodePtr->value)
insert(nodePtr->left, newNode); //Search left branch
else
insert(nodePtr->right, newNode); //search right branch
}
//
// Displays the number of nodes in the Tree
int IntBinaryTree::numberNodes(TreeNode *root)
{
TreeNode *nodePtr = root;
if(root == NULL)
return 0;
int count = 1; // our actual node
if(nodePtr->left !=NULL)
{ count += numberNodes(nodePtr->left);
}
if(nodePtr->right != NULL)
{
count += numberNodes(nodePtr->right);
}
return count;
}
// Insert member function
void IntBinaryTree::insertNode(string num)
{
TreeNode *newNode; // Poitner to a new node.
// Create a new node and store num in it.
newNode = new TreeNode;
newNode->value = num;
newNode->left = newNode->right = NULL;
//Insert the node.
insert(root, newNode);
}
// More member functions, etc.
BinarySearchTree.h:
class IntBinaryTree
{
private:
struct TreeNode
{
string value; // Value in the node
TreeNode *left; // Pointer to left child node
TreeNode *right; // Pointer to right child node
};
//Private Members Functions
// Removed for shortness
void displayInOrder(TreeNode *) const;
public:
TreeNode *root;
//Constructor
IntBinaryTree()
{ root = NULL; }
//Destructor
~IntBinaryTree()
{ destroySubTree(root); }
// Binary tree Operations
void insertNode(string);
// Removed for shortness
int numberNodes(TreeNode *root);
//int balancedTree(string, int, int); // TreeBalanced
bool leftRotation(TreeNode *root);
bool rightRotation(TreeNode *root);
bool doAVLBalance(TreeNode *root); // void doAVLBalance();
bool isAVLBalanced();
int calculateAndGetAVLBalanceFactor(TreeNode *root);
int getAVLBalanceFactor()
{
TreeNode *nodePtr = root; // Okay to do this? instead of just
// left->mDepth
// right->mDepth
int leftTreeDepth = (left !=NULL) ? nodePtr->left->Depth : -1;
int rightTreeDepth = (right != NULL) ? nodePtr->right->Depth : -1;
return(leftTreeDepth - rightTreeDepth);
}
bool isRightheavey() { return (getAVLBalanceFactor() <= -2); }
bool isLeftheavey() { return (getAVLBalanceFactor() >= 2); }
bool isBalanced()
{
int balanceFactor = getAVLBalanceFactor();
return (balanceFactor >= -1 && balanceFactor <= 1);
}
int getDepth(TreeNode *root); // getDepth
void displayInOrder() const
{ displayInOrder(root); }
// Removed for shortness
};
Programmers use AVL Tree concepts to balance binary trees. It is quite simple. More information can be found online. Quick wiki link
Below is the sample code which does tree balance using AVL algorithm.
Node *BinarySearchTree::leftRotation(Node *root)
{
if(NULL == root)
{
return NULL;
}
Node *rightOfTheRoot = root->mRight;
root->mRight = rightOfTheRoot->mLeft;
rightOfTheRoot->mLeft = root;
return rightOfTheRoot;
}
Node *BinarySearchTree::rightRotation(Node *root)
{
if(NULL == root)
{
return NULL;
}
Node *leftOfTheRoot = root->mLeft;
root->mLeft = leftOfTheRoot->mRight;
leftOfTheRoot->mRight = root;
return leftOfTheRoot;
}
Node *BinarySearchTree::doAVLBalance(Node *root)
{
if(NULL == root)
{
return NULL;
}
else if(root->isBalanced())
{
return root;
}
root->mLeft = doAVLBalance(root->mLeft);
root->mRight = doAVLBalance(root->mRight);
getDepth(root);
if(root->isRightHeavy())
{
if(root->mRight->isLeftHeavy())
{
root->mRight = rightRotation(root->mRight);
}
root = leftRotation(root);
}
else if(root->isLeftHeavy())
{
if(root->mLeft->isRightHeavy())
{
root->mLeft = leftRotation(root->mLeft);
}
root = rightRotation(root);
}
return root;
}
Class Definition
class BinarySearchTree
{
public:
// .. lots of methods
Node *getRoot();
int getDepth(Node *root);
bool isAVLBalanced();
int calculateAndGetAVLBalanceFactor(Node *root);
void doAVLBalance();
private:
Node *mRoot;
};
class Node
{
public:
int mData;
Node *mLeft;
Node *mRight;
bool mHasVisited;
int mDepth;
public:
Node(int data)
: mData(data),
mLeft(NULL),
mRight(NULL),
mHasVisited(false),
mDepth(0)
{
}
int getData() { return mData; }
void setData(int data) { mData = data; }
void setRight(Node *right) { mRight = right;}
void setLeft(Node *left) { mLeft = left; }
Node * getRight() { return mRight; }
Node * getLeft() { return mLeft; }
bool hasLeft() { return (mLeft != NULL); }
bool hasRight() { return (mRight != NULL); }
bool isVisited() { return (mHasVisited == true); }
int getAVLBalanceFactor()
{
int leftTreeDepth = (mLeft != NULL) ? mLeft->mDepth : -1;
int rightTreeDepth = (mRight != NULL) ? mRight->mDepth : -1;
return(leftTreeDepth - rightTreeDepth);
}
bool isRightHeavy() { return (getAVLBalanceFactor() <= -2); }
bool isLeftHeavy() { return (getAVLBalanceFactor() >= 2); }
bool isBalanced()
{
int balanceFactor = getAVLBalanceFactor();
return (balanceFactor >= -1 && balanceFactor <= 1);
}
};
There are many ways to do this, but I'd suggest that you actually not do this as all. If you want to store a BST of strings, there are much better options:
Use a prewritten binary search tree class. The C++ std::set class offers the same time guarantees as a balanced binary search tree and is often implemented as such. It's substantially easier to use than rolling you own BST.
Use a trie instead. The trie data structure is simpler and more efficient than a BST of strings, requires no balancing at all, and is faster than a BST.
If you really must write your own balanced BST, you have many options. Most BST implementations that use balancing are extremely complex and are not for the faint of heart. I'd suggest implementing either a treap or a splay tree, which are two balanced BST structures that are rather simple to implement. They're both more complex than the code you have above and I can't in this short space provide an implementation, but a Wikipedia search for these structures should give you plenty of advice on how to proceed.
Hope this helps!
Unfortunately, we programmers are literal beasts.
make it a "Balanced" tree.
"Balanced" is context dependent. The introductory data structures classes typically refer to a tree being "balanced" when the difference between the node of greatest depth and the node of least depth is minimized. However, as mentioned by Sir Templatetypedef, a splay tree is considered a balancing tree. This is because it can balance trees rather well in cases that few nodes accessed together at one time frequently. This is because it takes less node traversals to get at the data in a splay tree than a conventional binary tree in these cases. On the other hand, its worst-case performance on an access-by-access basis can be as bad as a linked list.
Speaking of linked lists...
Because otherwise without the "Balancing" it's the same as a linked-list I read and defeats the purpose.
It can be as bad, but for randomized inserts it isn't. If you insert already-sorted data, most binary search tree implementations will store data like an bloated and ordered linked list. However, that's only because you're building one side of the tree continually. (Imagine inserting 1, 2, 3, 4, 5, 6, 7, etc... into a binary tree. Try it on paper and see what happens.)
If you have to balance in a theoretical worst-case-must-guaranteed sense, I recommend looking up red-black trees. (Google it, second link is pretty good.)
If you have to balance it in a reasonable way for this particular scenario, I'd go with integer indices and a decent hash function -- that way the balancing will happen probabilistically without any extra code. That is to say, make your comparison function look like hash(strA) < hash(strB) instead of what you've got now. (For a quick but effective hash for this case, look up FNV hashing. First hit on Google. Go down until you see useful code.) You can worry about the details of implementation efficiency if you want to. (For example, you don't have to perform both hashes every single time you compare since one of the strings never changes.)
If you can get away with it, I strongly recommend the latter if you're in a crunch for time and want something fast. Otherwise, red-black trees are worthwhile since they're extremely useful in practice when you need to roll your own height-balanced binary trees.
Finally, addressing your code above, see the comments in the code below:
int IntBinaryTree::numberNodes(TreeNode *root)
{
if(root = NULL) // You're using '=' where you want '==' -- common mistake.
// Consider getting used to putting the value first -- that is,
// "NULL == root". That way if you make that mistake again, the
// compiler will error in many cases.
return 0;
/*
if(TreeNode.left=null && TreeNode.right==null) // Meant to use '==' again.
{ return 1; }
return numberNodes(node.left) + numberNodes(node.right);
*/
int count = 1; // our actual node
if (left != NULL)
{
// You likely meant 'root.left' on the next line, not 'TreeNode.left'.
count += numberNodes(TreeNode.left);
// That's probably the line that's giving you the error.
}
if (right != NULL)
{
count += numberNodes(root.right);
}
return count;
}
Related
I'm working on a inventory system and i had working Crafting system, now i wanted to create RPG like crafting queue where you can click like 3 times on a item and it wil lcraft for you 3 time if you have enough resources, and i started working on it but for some reason, the original crafting system broke, here is what happens when you want to craft something
When you click on Crafting Recipe:
//override Use Function
public override void Use() {
//call AddCraftingItem from Inventory
Inventory.instance.AddCraftingItem(this);
}
AddCraftingItem:
public void AddCraftingItem(CraftinRecipe newCraftingRecipe) {
CraftingQueue.Enqueue(newCraftingRecipe);
if(!isCrafting) {
isCrafting = true;
//start crafting
StartCoroutine(CraftItem());
}
}
CraftItem:
private IEnumerator CraftItem() {
//check if queue is empty
if(CraftingQueue.Count == 0) {
Debug.Log("Queue is empty");
isCrafting = false;
yield break;
}
CraftinRecipe currentRecipe = CraftingQueue.Dequeue();
//check if we have enough resources
//this is where things broke
//CraftItem return false
if(!currentRecipe.CraftItem()) {
//Debug.Log("You don't have enough Resources");
CraftingQueue.Clear();
isCrafting = false;
yield break;
}
Debug.Log("TEST");
yield return new WaitForSeconds(currentRecipe.craftTime * 1.1f);
//add item to inventory
AddItem(currentRecipe.result);
Debug.Log("Added " + currentRecipe.result + " to inventory");
//check if continue crafting
if(CraftingQueue.Count > 0) {
yield return StartCoroutine(CraftItem());
} else {
isCrafting = false;
}
}
CraftItem:
public bool CraftItem() {
if(!CanCraft()) {
//Debug.Log("CanCraft returned false");
return false;
} else {
Debug.Log("CanCraft returned true");
}
RemoveIngredientsFromInventory();
//start crafting
ParentCraftingSlot.StartCrafting();
return true;
}
CanCraft function:
//function that return bool if we can craft the Item
public bool CanCraft() {
//loop trough each ingredient type of ingredient in ingredient
//(don't worry bro i don't understand what i just said too)
foreach(Ingredient ingredient in ingredients) {
//bool if we Contains current Ingredients
//here this function return false
bool ContainsCurrentIngredient = Inventory.instance.ContainsItem(ingredient.item,
ingredient.amount);
//if ContainsCurrentIngredient is false
if(!ContainsCurrentIngredient) {
//we return false
return false;
}
}
//return true
return true;
}
ContainItems (this is where things are broken):
//function that return true or false
//if we have enough Item to craft something
public bool ContainsItem(Item item, int amount) {
//make some variables objects etc
int ItemCounter = 0;
//loop through InventoryItemList with variable i type of Item
//(don't worry i don't know what i just said too #6)
foreach(Item i in InventoryItemList) {
//if i is equal to item
//this is the broken part
if(i == item) {
Debug.Log(i);
Debug.Log(item);
//we add 1 to Item Counter
ItemCounter++;
} else {
Debug.Log("i is not equal to item");
}
}
//if ItemCounter is bigger then or equal to amount
if(ItemCounter >= amount) {
/*Debug.Log("ContainsItem returned true");
Debug.Log(ItemCounter);*/
//we return true
//that means we have enough items to craft something
return true;
} else /*else*/ {
/*Debug.Log("ContainsItem returned false");
Debug.Log(ItemCounter);*/
//we return false
//that means we don't have enough item to craft something
return false;
}
}
so the problem is, in the InventoryItemList there are clones of one item, lets just say i have 2 irons and i need 1 iron to craft something, and my guess is that the problem is that i is clone so its not equal to the item and thats why it doesn't add 1 to itemCounter and then the script thinks we don't have enough resources to craft something, i tried to search and ask some of my friends how to check if that clone is equal to the item and i'm trying to fix this thing for like 2 days, i would love to hear any answers how to fix it or how to make my code more optimal, thanks for reading
Instead of directly checking i == item have some property in Item class which contains information of item type something like following
public class item
{
public enum Type
{
IronBar, GoldBar //etc
}
public Type itemType;
}
Then in your ContainItems() you could use something like
public bool ContainsItem(Item.Type itemType, int amount){
// other code
foreach(Item i in InventoryItemList) {
if(i.itemType == itemType) {
ItemCounter++;
}
// other code
}
So when writing UI in GTK it's generally preferrable to handle reading of files, etc. in an Async Method. things such as listboxes, are generally bound to a ListModel, the items in the ListBox updated in accordance with the items_changed signal.
So if I have some class, that implements ListModel, and has an add function, and some FileReader that holds a reference to said ListModel, and call add from an async function, how do i make that in essence triggering the items_changed and having GTK update accordingly?
I've tried list.items_changed.connect(message("Items changed!")); but it never triggers.
I saw this: How can one update GTK+ UI in Vala from a long operation without blocking the UI
but in this example, it's just the button label that is changed, no signal is actually triggered.
EDIT: (Codesample added at the request of #Michael Gratton
//Disclaimer: everything here is still very much a work in progress, and will, as soon as I'm confident that what I have is not total crap, be released under some GPL or other open license.
//Note: for the sake of readability, I adopted the C# naming convention for interfaces, namely, putting a capital 'I' in front of them, a decision i do not feel quite as confident in as I did earlier.
//Note: the calls to message(..) was put in here to help debugging
public class AsyncFileContext : Object{
private int64 offset;
private bool start_read;
private bool read_to_end;
private Factories.IVCardFactory factory;
private File file;
private FileMonitor monitor;
private Gee.Set<IVCard> vcard_buffer;
private IObservableSet<IVCard> _vCards;
public IObservableSet<IVCard> vCards {
owned get{
return this._vCards;
}
}
construct{
//We want to start fileops at the beginning of the file
this.offset = (int64)0;
this.start_read = true;
this.read_to_end = false;
this.vcard_buffer = new Gee.HashSet<IVCard>();
this.factory = new Factories.GenericVCardFactory();
}
public void add_vcard(IVCard card){
//TODO: implement
}
public AsyncFileContext(IObservableSet<IVCard> vcards, string path){
this._vCards = vcards;
this._vCards = IObservableSet.wrap_set<IVCard>(new Gee.HashSet<IVCard>());
this.file = File.new_for_path(path);
this.monitor = file.monitor_file(FileMonitorFlags.NONE, null);
message("1");
//TODO: add connect
this.monitor.changed.connect((file, otherfile, event) => {
if(event != FileMonitorEvent.DELETED){
bool changes_done = event == FileMonitorEvent.CHANGES_DONE_HINT;
Idle.add(() => {
read_file_async.begin(changes_done);
return false;
});
}
});
message("2");
//We don't know that changes are done yet
//TODO: Consider carefully how you want this to work when it is NOT called from an event
Idle.add(() => {
read_file_async.begin(false);
return false;
});
}
//Changes done should only be true if the FileMonitorEvent that triggers the call was CHANGES_DONE_HINT
private async void read_file_async(bool changes_done) throws IOError{
if(!this.start_read){
return;
}
this.start_read = false;
var dis = new DataInputStream(yield file.read_async());
message("3");
//If we've been reading this file, and there's then a change, we assume we need to continue where we let off
//TODO: assert that the offset isn't at the very end of the file, if so reset to 0 so we can reread the file
if(offset > 0){
dis.seek(offset, SeekType.SET);
}
string line;
int vcards_added = 0;
while((line = yield dis.read_line_async()) != null){
message("position: %s".printf(dis.tell().to_string()));
this.offset = dis.tell();
message("4");
message(line);
//if the line is empty, we want to jump to next line, and ignore the input here entirely
if(line.chomp().chug() == ""){
continue;
}
this.factory.add_line(line);
if(factory.vcard_ready){
message("creating...");
this.vcard_buffer.add(factory.create());
vcards_added++;
//If we've read-in and created an entire vcard, it's time to yield
message("Yielding...");
Idle.add(() => {
_vCards.add_all(vcard_buffer);
vcard_buffer.remove_all(_vCards);
return false;
});
Idle.add(read_file_async.callback);
yield;
message("Resuming");
}
}
//IF we expect there will be no more writing, or if we expect that we read ALL the vcards, and did not add any, it's time to go back and read through the whole thing again.
if(changes_done){ //|| vcards_added == 0){
this.offset = 0;
}
this.start_read = true;
}
}
//The main idea in this class is to just bind the IObservableCollection's item_added, item_removed and cleared signals to the items_changed of the ListModel. IObservableCollection is a class I have implemented that merely wraps Gee.Collection, it is unittested, and works as intended
public class VCardListModel : ListModel, Object{
private Gee.List<IVCard> vcard_list;
private IObservableCollection<IVCard> vcard_collection;
public VCardListModel(IObservableCollection<IVCard> vcard_collection){
this.vcard_collection = vcard_collection;
this.vcard_list = new Gee.ArrayList<IVCard>.wrap(vcard_collection.to_array());
this.vcard_collection.item_added.connect((vcard) => {
vcard_list.add(vcard);
int pos = vcard_list.index_of(vcard);
items_changed(pos, 0, 1);
});
this.vcard_collection.item_removed.connect((vcard) => {
int pos = vcard_list.index_of(vcard);
vcard_list.remove(vcard);
items_changed(pos, 1, 0);
});
this.vcard_collection.cleared.connect(() => {
items_changed(0, vcard_list.size, 0);
vcard_list.clear();
});
}
public Object? get_item(uint position){
if((vcard_list.size - 1) < position){
return null;
}
return this.vcard_list.get((int)position);
}
public Type get_item_type(){
return Type.from_name("VikingvCardIVCard");
}
public uint get_n_items(){
return (uint)this.vcard_list.size;
}
public Object? get_object(uint position){
return this.get_item((int)position);
}
}
//The IObservableCollection parsed to this classes constructor, is the one from the AsyncFileContext
public class ContactList : Gtk.ListBox{
private ListModel list_model;
public ContactList(IObservableCollection<IVCard> ivcards){
this.list_model = new VCardListModel(ivcards);
bind_model(this.list_model, create_row_func);
list_model.items_changed.connect(() => {
message("Items Changed!");
base.show_all();
});
}
private Gtk.Widget create_row_func(Object item){
return new ContactRow((IVCard)item);
}
}
Heres the way i 'solved' it.
I'm not particularly proud of this solution, but there are a couple of awful things about the Gtk ListBox, one of them being (and this might really be more of a ListModel issue) if the ListBox is bound to a ListModel, the ListBox will NOT be sortable by using the sort method, and to me at least, that is a dealbreaker. I've solved it by making a class which is basically a List wrapper, which has an 'added' signal and a 'remove' signal. Upon adding an element to the list, the added signal is then wired, so it will create a new Row object and add it to the list box. That way, data is control in a manner Similar to ListModel binding. I can not make it work without calling the ShowAll method though.
private IObservableCollection<IVCard> _ivcards;
public IObservableCollection<IVCard> ivcards {
get{
return _ivcards;
}
set{
this._ivcards = value;
foreach(var card in this._ivcards){
base.prepend(new ContactRow(card));
}
this._ivcards.item_added.connect((item) => {
base.add(new ContactRow(item));
base.show_all();
});
base.show_all();
}
}
Even though this is by no means the best code I've come up with, it works very well.
I have a List<ImmutableList<T>>. I want to flatten it into a single ImmutableList<T> that is a concatenation of all the internal ImmutableLists. These lists can be very long so I do not want this operation to perform a copy of all the elements. The number of ImmutableLists to flatten will be relatively small, so it is fine that lookup will be linear in the number of ImmutableLists. I would strongly prefer that the concatenation will return an Immutable collection. And I need it to return a List that can be accessed in a random location.
Is there a way to do this in Guava?
There is Iterables.concat but that returns an Iterable. To convert this into an ImmutableList again will be linear in the size of the lists IIUC.
By design Guava does not allow you to define your own ImmutableList implementations (if it did, there'd be no way to enforce that it was immutable). Working around this by defining your own class in the com.google.common.collect package is a terrible idea. You break the promises of the Guava library and are running firmly in "undefined behavior" territory, for no benefit.
Looking at your requirements:
You need to concatenate the elements of n ImmutableList instances in sub-linear time.
You would like the result to also be immutable.
You need the result to implement List, and possibly be an ImmutableList.
As you know you can get the first two bullets with a call to Iterables.concat(), but if you need an O(1) random-access List this won't cut it. There isn't a standard List implementation (in Java or Guava) that is backed by a sequence of Lists, but it's straightforward to create one yourself:
/**
* A constant-time view into several {#link ImmutableList} instances, as if they were
concatenated together. Since the backing lists are immutable this class is also
immutable and therefore thread-safe.
*
* More precisely, this class provides O(log n) element access where n is the number of
* input lists. Assuming the number of lists is small relative to the total number of
* elements this is effectively constant time.
*/
public class MultiListView<E> extends AbstractList<E> implements RandomAccess {
private final ImmutableList<ImmutableList<E>> elements;
private final int size;
private final int[] startIndexes;
private MutliListView(Iterable<ImmutableList<E>> elements) {
this.elements = ImmutableList.copyOf(elements);
startIndexes = new int[elements.size()];
int currentSize = 0;
for (int i = 0; i < this.elements.size(); i++) {
List<E> ls = this.elements.get(i);
startIndexes[i] = ls.size();
currentSize += ls.size();
}
}
#Override
public E get(int index) {
checkElementIndex(index, size);
int location = Arrays.binarySearch(startIndexes, index);
if (location >= 0) {
return elements.get(location).get(0);
}
location = (~location) - 1;
return elements.get(location).get(index - startIndexes[location]);
}
#Override
public int size() {
return size;
}
// The default iterator returned by AbstractList.iterator() calls .get()
// which is likely slower than just concatenating the backing lists' iterators
#Override
public Iterator<E> iterator() {
return Iterables.concat(elements).iterator();
}
public static MultiListView<E> of(Iterable<ImmutableList<E>> lists) {
return new MultiListView<>(lists);
}
public static MultiListView<E> of(ImmutableList<E> ... lists) {
return of(Arrays.asList(lists));
}
}
This class is immutable even though it doesn't extend ImmutableList or ImmutableCollection, therefore there's no need for it to actually extend ImmutableList.
As to whether such a class should be provided by Guava; you can make your case in the associated issue, but the reason this doesn't already exist is that surprisingly few users actually need it. Be sure there isn't a reasonable way to solve your problem with an Iterable before using MultiListView.
Firstly, #dimo414's answer is right on the mark - with a clean wrapper view implementation and advice.
Still, I would like to emphasise that since Java 8, you probably just want to do:
listOfList.stream()
.flatMap(ImmutableList::stream)
.collect(ImmutableList.toImmutableList());
The guava issue was since closed as working-as-intended with the remark:
We are more down on lazy view collections than we used to be (especially now that Stream exists) (...)
At least, profile your own use case before trying the view-collection approach.
Under the hood using streams, what effectively happens is that a new backing array is populated with references to the elements - the elements themselves are not deeply copied. So there's very low number of objects created (GC costs) and linear copies from backing-arrays to backing-arrays usually proceed faster than you might expect even with large inner-lists. (They work well with CPU cache prefetch).
Depending on how much you do with the result, the stream version might work out faster that the wrapper version's extra indirection every time you access it.
Here is probably a slightly more readable version of dimo414 implementation, which processes empty lists correctly and populates startIndexes correctly:
public class ImmutableMultiListView<E> extends AbstractList<E> implements RandomAccess {
private final ImmutableList<ImmutableList<E>> listOfLists;
private final int[] startIndexes;
private final int size;
private ImmutableMultiListView(List<ImmutableList<E>> originalListOfLists) {
this.listOfLists =
originalListOfLists.stream().filter(l -> !l.isEmpty()).collect(toImmutableList());
startIndexes = new int[listOfLists.size()];
int sumSize = 0;
for (int i = 0; i < listOfLists.size(); i++) {
List<E> list = listOfLists.get(i);
sumSize += list.size();
if (i < startIndexes.length - 1) {
startIndexes[i + 1] = sumSize;
}
}
this.size = sumSize;
}
#Override
public E get(int index) {
checkElementIndex(index, size);
int location = Arrays.binarySearch(startIndexes, index);
if (location >= 0) {
return listOfLists.get(location).get(0);
} else {
// See Arrays#binarySearch Javadoc:
int insertionPoint = -location - 1;
int listIndex = insertionPoint - 1;
return listOfLists.get(listIndex).get(index - startIndexes[listIndex]);
}
}
#Override
public int size() {
return size;
}
// AbstractList.iterator() calls .get(), which is slower than just concatenating
// the backing lists' iterators
#Override
public Iterator<E> iterator() {
return Iterables.concat(listOfLists).iterator();
}
public static <E> ImmutableMultiListView<E> of(List<ImmutableList<E>> lists) {
return new ImmutableMultiListView<>(lists);
}
}
Not sure if it is possible just with Guava classes, but it seems not difficult to implement, how about something like the following:
package com.google.common.collect;
import java.util.List;
public class ConcatenatedList<T> extends ImmutableList<T> {
private final List<ImmutableList<T>> underlyingLists;
public ConcatenatedList(List<ImmutableList<T>> underlyingLists) {
this.underlyingLists = underlyingLists;
}
#Override
public T get(int index) {
for (ImmutableList<T> list : underlyingLists) {
if (index < list.size()) return list.get(index);
index -= list.size();
}
throw new IndexOutOfBoundsException();
}
#Override
boolean isPartialView() {
for (ImmutableList<T> list : underlyingLists) {
if (list.isPartialView()) return true;
}
return false;
}
#Override
public int size() {
int result = 0;
for (ImmutableList<T> list : underlyingLists) {
result += list.size();
}
return result;
}
}
Note package declaration, it needs to be like that to access Guava's ImmutableList package access constructor. Be aware that this implementation might break with future version of Guava, since the constructor is not part of API. Also as mentioned in the javadoc of ImmutableList and in comments this class was not intended to be subclassed by the original library author. However, there is no good reason for not using it in application you control and it has additional benefit of expressing immutability in the type signature compared to MultiListView suggested in the other answer.
In the top of the Hierarchy window of the Unity Editor there is a field for filtering the hierarchy:
My question is if you can set that filter from an editor script and how. I can barely find anything according to this on the web.
Thanks in advance.
UnityEditor.SceneModeUtility.SearchForType seems to be a step in the right direction.
The good news is, that you can see the implementation of that method in MonoDevelop..
Taking a closer look at it tells us the methods we'd need.
public static void SearchForType (Type type)
{
Object[] array = Resources.FindObjectsOfTypeAll (typeof(SceneHierarchyWindow));
SceneHierarchyWindow sceneHierarchyWindow = (array.Length <= 0) ? null : (array [0] as SceneHierarchyWindow);
if (sceneHierarchyWindow)
{
SceneModeUtility.s_HierarchyWindow = sceneHierarchyWindow;
if (type == null || type == typeof(GameObject))
{
SceneModeUtility.s_FocusType = null;
sceneHierarchyWindow.ClearSearchFilter ();
}
else
{
SceneModeUtility.s_FocusType = type;
if (sceneHierarchyWindow.searchMode == SearchableEditorWindow.SearchMode.Name)
{
sceneHierarchyWindow.searchMode = SearchableEditorWindow.SearchMode.All;
}
sceneHierarchyWindow.SetSearchFilter ("t:" + type.Name, sceneHierarchyWindow.searchMode, false);
sceneHierarchyWindow.hasSearchFilterFocus = true;
}
}
else
{
SceneModeUtility.s_FocusType = null;
}
}
And now the bad news, due to their protection level, you can neither access the hierarchy window directly, nor can you use the SetSearchFilter method.
Maybe you could write an editor script, similar to the hierarchy view, where you have full control, and can do whatever you want.
Thanks to d4RK I found out how to do it using Reflection:
public const int FILTERMODE_ALL = 0;
public const int FILTERMODE_NAME = 1;
public const int FILTERMODE_TYPE = 2;
public static void SetSearchFilter(string filter, int filterMode) {
SearchableEditorWindow[] windows = (SearchableEditorWindow[])Resources.FindObjectsOfTypeAll (typeof(SearchableEditorWindow));
foreach (SearchableEditorWindow window in windows) {
if(window.GetType().ToString() == "UnityEditor.SceneHierarchyWindow") {
hierarchy = window;
break;
}
}
if (hierarchy == null)
return;
MethodInfo setSearchType = typeof(SearchableEditorWindow).GetMethod("SetSearchFilter", BindingFlags.NonPublic | BindingFlags.Instance);
object[] parameters = new object[]{filter, filterMode, false};
setSearchType.Invoke(hierarchy, parameters);
}
This may not be the most elegant way, but it works like a charm and can easily be extended to apply the same filter to the SceneView.
As of Unity 2018 there is an additional boolean parameter required for the SetSearchFilter method.
So change this line
object[] parameters = new object[]{filter, filterMode, false};
to
object[] parameters = new object[]{filter, filterMode, false, false};
This should resolve the TargetParameterCountException Ugo Hed mentioned.
I'm trying to implement a caching scheme for my EF Repository similar to the one blogged here. As the author and commenters have reported the limitation is that the key generation method cannot produce cache keys that vary with a given query's parameters. Here is the cache key generation method:
private static string GetKey<T>(IQueryable<T> query)
{
string key = string.Concat(query.ToString(), "\n\r",
typeof(T).AssemblyQualifiedName);
return key;
}
So the following queries will yield the same cache key:
var isActive = true;
var query = context.Products
.OrderBy(one => one.ProductNumber)
.Where(one => one.IsActive == isActive).AsCacheable();
and
var isActive = false;
var query = context.Products
.OrderBy(one => one.ProductNumber)
.Where(one => one.IsActive == isActive).AsCacheable();
Notice that the only difference is that isActive = true in the first query and isActive = false in the second.
Any suggestions/insight to efficiently generating cache keys which vary by IQueryable parameters would be truly appreciated.
Kudos to Sergey Barskiy for sharing the EF CodeFirst caching scheme.
Update
I took the approach of traversing the IQueryable's expression tree myself with the goal of resolving the values of the parameters used in the query. With maxlego's suggestion, I extended the System.Linq.Expressions.ExpressionVisitor class to visit the expression nodes that we're interested in - in this case, the MemberExpression. The updated GetKey method looks something like this:
public static string GetKey<T>(IQueryable<T> query)
{
var keyBuilder = new StringBuilder(query.ToString());
var queryParamVisitor = new QueryParameterVisitor(keyBuilder);
queryParamVisitor.GetQueryParameters(query.Expression);
keyBuilder.Append("\n\r");
keyBuilder.Append(typeof (T).AssemblyQualifiedName);
return keyBuilder.ToString();
}
And the QueryParameterVisitor class, which was inspired by the answers of Bryan Watts and Marc Gravell to this question, looks like this:
/// <summary>
/// <see cref="ExpressionVisitor"/> subclass which encapsulates logic to
/// traverse an expression tree and resolve all the query parameter values
/// </summary>
internal class QueryParameterVisitor : ExpressionVisitor
{
public QueryParameterVisitor(StringBuilder sb)
{
QueryParamBuilder = sb;
Visited = new Dictionary<int, bool>();
}
protected StringBuilder QueryParamBuilder { get; set; }
protected Dictionary<int, bool> Visited { get; set; }
public StringBuilder GetQueryParameters(Expression expression)
{
Visit(expression);
return QueryParamBuilder;
}
private static object GetMemberValue(MemberExpression memberExpression, Dictionary<int, bool> visited)
{
object value;
if (!TryGetMemberValue(memberExpression, out value, visited))
{
UnaryExpression objectMember = Expression.Convert(memberExpression, typeof (object));
Expression<Func<object>> getterLambda = Expression.Lambda<Func<object>>(objectMember);
Func<object> getter = null;
try
{
getter = getterLambda.Compile();
}
catch (InvalidOperationException)
{
}
if (getter != null) value = getter();
}
return value;
}
private static bool TryGetMemberValue(Expression expression, out object value, Dictionary<int, bool> visited)
{
if (expression == null)
{
// used for static fields, etc
value = null;
return true;
}
// Mark this node as visited (processed)
int expressionHash = expression.GetHashCode();
if (!visited.ContainsKey(expressionHash))
{
visited.Add(expressionHash, true);
}
// Get Member Value, recurse if necessary
switch (expression.NodeType)
{
case ExpressionType.Constant:
value = ((ConstantExpression) expression).Value;
return true;
case ExpressionType.MemberAccess:
var me = (MemberExpression) expression;
object target;
if (TryGetMemberValue(me.Expression, out target, visited))
{
// instance target
switch (me.Member.MemberType)
{
case MemberTypes.Field:
value = ((FieldInfo) me.Member).GetValue(target);
return true;
case MemberTypes.Property:
value = ((PropertyInfo) me.Member).GetValue(target, null);
return true;
}
}
break;
}
// Could not retrieve value
value = null;
return false;
}
protected override Expression VisitMember(MemberExpression node)
{
// Only process nodes that haven't been processed before, this could happen because our traversal
// is depth-first and will "visit" the nodes in the subtree before this method (VisitMember) does
if (!Visited.ContainsKey(node.GetHashCode()))
{
object value = GetMemberValue(node, Visited);
if (value != null)
{
QueryParamBuilder.Append("\n\r");
QueryParamBuilder.Append(value.ToString());
}
}
return base.VisitMember(node);
}
}
I'm still doing some performance profiling on the cache key generation and hoping that it isn't too expensive (I'll update the question with the results once I have them). I'll leave the question open, in case anyone has suggestions on how to optimize this process or has a recommendation for a more efficient method for generating cache keys with vary with the query parameters. Although this method produces the desired output, it is by no means optimal.
i suggest to use ExpressionVisitor
http://msdn.microsoft.com/en-us/library/bb882521(v=vs.90).aspx
Just for the record, "Caching the results of LINQ queries" works well with the EF and it's able to work with parameters correctly, so it can be considered as a good second level cache implementation for EF.
While the solution of the OP works quite well, I found that the performance of the solution is a little bit poor.
The duration of the key generation varied between 300ms and 1200ms for my queries.
However, I've found another solution that has quite better performance (<10ms).
public static string ToTraceString<T>(DbQuery<T> query)
{
var internalQueryField = query.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(f => f.Name.Equals("_internalQuery")).FirstOrDefault();
var internalQuery = internalQueryField.GetValue(query);
var objectQueryField = internalQuery.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(f => f.Name.Equals("_objectQuery")).FirstOrDefault();
var objectQuery = objectQueryField.GetValue(internalQuery) as ObjectQuery<T>;
return ToTraceStringWithParameters(objectQuery);
}
private static string ToTraceStringWithParameters<T>(ObjectQuery<T> query)
{
string traceString = query.ToTraceString() + "\n";
foreach (var parameter in query.Parameters)
{
traceString += parameter.Name + " [" + parameter.ParameterType.FullName + "] = " + parameter.Value + "\n";
}
return traceString;
}