So basically what I have to do is add crabcritters to gridworld randomly, which I did. Then, I need to use the getOccupiedLocations method to print an array of the occupied locations as ordered pairs. Any advice? Here's what I have so far:
package projects.critters;
import info.gridworld.actor.ActorWorld;
import info.gridworld.grid.Location;
public class Lab
{
public static void main (String[] args)
{
ActorWorld world = new ActorWorld();
for (int i =0; i<10; i++)
{
world.add (new CrabCritter());
}
world.show();
}
}
OK so the method getOccupiedLocations() returns an array of Locations. I don't know exactly what you mean by ordered pairs but if you mean (x, y) then that is easy to do. By default when you print out a Location it is an ordered pair. So all you have to do is loop through the occupied locations and print each out. For example:
for(Location l : world.getGrid().getOccupiedLocations()){
System.out.println(l);
}
And that's it...as for the comment: you don't need a language tag as this is a GridWorld question which obviously applies to Java.
Expanding on John Smith's answer. If you only want to print locations occupied by CrabCritter only, you can do this:
for(Location l : world.getGrid().getOccupiedLocations()){
if(world.get(l) instanceof CrabCritter)
System.out.println(l);
}
Related
I have a list of elements and I need to get a list containing the first element followed by every nth element afterwards. For example: given n = 3 and the list [banana, cherry, apple, pear, kiwi], I need to get the list [banana, pear]. I need this regardless of specific content, since the list depends on user input.
How do I do this using Dart?
You may access list in dart by providing an index like for example:
List<String> fruits = ["banana","cherry","apple","pear","kiwi"];
print(fruits[0]); // Will print to the console "banana";
On your case, you are trying to access index 0 and index 3 which is "banana" and "pear".
You may create a function that accepts an index like:
String getFruit(int index, List<String> fruits) => fruits[index];
print(getFruit[0]); // Will print "banana";
or if you need to actually get the specific ranges you may use:
List<String> fruits =["banana","cherry","apple","pear","kiwi"].getRange(0,4);
// Will give you "banana","cherry","apple","pear
You may check : https://api.dart.dev/be/180791/dart-core/List-class.html for more information.
Edited answer based off the comment:
List<String> getElements(List userInput, nIndex){
List elements = [];
for(int x = 0; x<userInput.length;x++){
if(x % nIndex == 0){
elements.add(userInput[x]);
}
}
return elements;
}
List fruits = ["banana","cherry","apple","pear","kiwi"];
print(getElements(fruits,2));
or you may try to look and use List.retainWhere() depending on your use case.
Dart has a great set of collection operators that make this type of problem pretty straightforward to solve. For example, we could do something like:
extension X<T> on List<T> {
List<T> everyNth(int n) => [for (var i = 0; i < this.length; i += n) this[i]];
}
main() {
final fruit = ["banana", "cherry", "apple", "pear", "kiwi"];
print(fruit.everyNth(3));
}
Output:
[banana, pear]
You can use this extension method, which will work on lists of any type:
extension GetEveryN<T> on List<T> {
List<T> elementsEveryN(int n) {
List<T> result = [];
for(int index = 0; index < length; index +=1) {
if(index % n == 0) {
result.add(this[index]);
}
}
return result;
}
}
Trying it in an example:
List<String> list = ["banana", "cherry","apple", "pear","kiwi"];
print(list.elementsEveryN(2)); // [banana, pear]
I have a situation where I have a list that can be at most 4 elements.
However, if I have only 1-3 elements to put in that list, how can I fill the remainder with null values?
For example, a List<int?> of length 4 with 2 given elements, should result in:
[1,3] -> [1,3,null,null]
Here's what I'm doing, but maybe there is a better way
List.generate(4, (index) {
try {
final id = given.elementAt(index);
return id;
} catch (error) {
return null;
}
});
The simplest version would probably be:
[for (var i = 0; i < 4; i++) i < given.length ? given[i] : null]
You can use List.generate, but in this case, the function is simple enough that a list literal can do the same thing more efficiently.
(Or, as #jamesdlin says, if you want a fixed-length list, use List.generate).
A more indirect variant could be:
List<GivenType?>.filled(4, null)..setAll(0, given)
where you create a list of four nulls first, then write the given list into it. It's probably just more complicated and less efficient.
Assume I want to concatenate N Uint8Lists into a single one.
The naive approach is to simple copy all elements into a new list. However, that seems rather memory in efficient. Instead, I want to create a single Uint8List "view" which simply indexes into the appropriate underlying list instead of copying all its content.
In C++ I'd usually just overwrite operator[] but I am not quite certain how to do this with Uint8Lists in Dart.
In C++, you can make a View class that overrides operator[]. In Dart, you could do the same thing:
class View<T> {
View(this._lists);
List<List<T>> _lists;
T operator [](int index) {
for (var list in _lists) {
if (index < list.length) {
return list[index];
}
index -= list.length;
}
throw RangeError('...');
}
}
You could stop there, but doing just that usually wouldn't be enough in either language. In C++, you'd also want to provide begin() and end() methods for range-based for loops to work. Similarly, in Dart, you'd want to provide the Iterable interface so that for-in would work.
Luckily package:collection (note that this is separate from dart:collection) provides a CombinedListView class that does that work for you. For example:
import 'dart:typed_data';
import 'package:collection/collection.dart';
void main() {
var list1 = Uint8List.fromList([1, 2, 3]);
var list2 = Uint8List.fromList([4, 5, 6]);
var list3 = Uint8List.fromList([7, 8, 9]);
var view = CombinedListView<int>([list1, list2, list3]);
for (var i in view) {
print(i);
}
}
I am trying to use a HashMap of Lists of strings in Vala, but it seems the object lifecycle is biting me. Here is my current code:
public class MyClass : CodeVisitor {
GLib.HashTable<string, GLib.List<string>> generic_classes = new GLib.HashTable<string, GLib.List<string>> (str_hash, str_equal);
public override void visit_data_type(DataType d) {
string c = ...
string s = ...
if (! this.generic_classes.contains(c)) {
this.generic_classes.insert(c, new GLib.List<string>());
}
unowned GLib.List<string> l = this.generic_classes.lookup(c);
bool is_dup = false;
foreach(unowned string ss in l) {
if (s == ss) {
is_dup = true;
}
}
if ( ! is_dup) {
l.append(s);
}
}
Note that I am adding a string value into the list associated with a string key. If the list doesn't exist, I create it.
Lets say I run the code with the same values of c and s three times. Based some printf debugging, it seems that only one list is created, yet each time it is empty. I'd expect the list of have size 0, then 1, and then 1. Am I doing something wrong when it comes to the Vala memory management/reference counting?
GLib.List is the problem here. Most operations on GLib.List and GLib.SList return a modified pointer, but the value in the hash table isn't modified. It's a bit hard to explain why that is a problem, and why GLib works that way, without diving down into the C. You have a few choices here.
Use one of the containers in libgee which support multiple values with the same key, like Gee.MultiMap. If you're working on something in the Vala compiler (which I'm guessing you are, as you're subclassing CodeVisitor), this isn't an option because the internal copy of gee Vala ships with doesn't include MultiMap.
Replace the GLib.List instances in the hash table. Unfortunately this is likely going to mean copying the whole list every time, and even then getting the memory management right would be a bit tricky, so I would avoid it if I were you.
Use something other than GLib.List. This is the way I would go if I were you.
Edit: I recently added GLib.GenericSet to Vala as an alternative binding for GHashTable, so the best solution now would be to use GLib.HashTable<string, GLib.GenericSet<string>>, assuming you're okay with depending on vala >= 0.26.
If I were you, I would use GLib.HashTable<string, GLib.HashTable<unowned string, string>>:
private static int main (string[] args) {
GLib.HashTable<string, GLib.HashTable<unowned string, string>> generic_classes =
new GLib.HashTable<string, GLib.HashTable<unowned string, string>> (GLib.str_hash, GLib.str_equal);
for (int i = 0 ; i < 3 ; i++) {
string c = "foo";
string s = i.to_string ();
unowned GLib.HashTable<unowned string, string>? inner_set = generic_classes[c];
stdout.printf ("Inserting <%s, %s>, ", c, s);
if (inner_set == null) {
var v = new GLib.HashTable<unowned string, string> (GLib.str_hash, GLib.str_equal);
inner_set = v;
generic_classes.insert ((owned) c, (owned) v);
}
inner_set.insert (s, (owned) s);
stdout.printf ("container now holds:\n");
generic_classes.foreach ((k, v) => {
stdout.printf ("\t%s:\n", k);
v.foreach ((ik, iv) => {
stdout.printf ("\t\t%s\n", iv);
});
});
}
return 0;
}
It may seem hackish to have a hash table with the key and value having the same value, but this is actually a common pattern in C as well, and specifically supported by GLib's hash table implementation.
Moral of the story: don't use GLib.List or GLib.SList unless you really know what you're doing, and even then it's generally best to avoid them. TBH we probably would have marked them as deprecated in Vala long ago if it weren't for the fact that they're very common when working with C APIs.
Vala's new can be a little weird when used as a parameter. I would recommend assigning the new list to a temporary, adding it to the list, then letting it go out of scope.
I would also recommend using libgee. It has better handling of generics than GLib.List and GLib.HashTable.
I have one line data like this:
a\tb1,b2,..,bn\tc1,c2,..,cn
in which n is uncertain. And now, I want transform it to some lines like this:
a\tb1\tc1
a\tb2\tc2
...
a\tbn\tcn
Is it possible by pig latin, or has to use UDF?
If using the script:
A = LOAD 'file' AS (a, b, c);
B = FOREACH A GENERATE a, FLATTEN(TOKENIZE(b)), FLATTEN(TOKENIZE(c));
dump B;
I will get the resulr as following:
a\tb1\tc1
a\tb1\tc2
..
a\tb1\tcn
a\tb2\tc1
a\tb2\tc2
..
a\tb2\tcn
..
It isn't the data I wanted. Does anyone have ideas?
IMO too many people who use Pig are resistant to write UDFs. In your case, the UDF you'd need to do this is fairly simple. Here's sample code (untested)
public class InSequenceJoin extends EvalFunc<DataBag>
{
public DataBag exec(Tuple input) throws IOException {
String b = (String) input.get(0);
String c = (String) input.get(1);
String[] bArray = b.split(",");
String[] cArray = c.split(",");
DataBag bag = BagFactory.getInstance().newDefaultBag();
for (int i = 0; i < bArray.length && i < cArray.length; i++) {
Tuple tuple = TupleFactory.getInstance.newTuple(2);
tuple.set(0, bArray[i]);
tuple.set(1, cArray[i]);
bag.add(tuple);
}
return bag;
}
}
define InSequenceJoin mysourcepath.InSequenceJoin();
A = LOAD 'file' AS (a, b, c);
B = FOREACH A GENERATE a, FLATTEN(InSequenceJoin(b,c));
dump B;
You could add validation on if the sizes of the arrays match if you need to in the UDF. You could replace the String split I used in example with whatever you truly require.
I'd try to use datafu's bag UDFs.
Load the data as you've done, then use Enumerate to enumerate the bag elements, then flatten (which gives you the cross join between the bag elements as you've seen) and then you can filter on the indexes added to the bag elements.
See here: https://github.com/linkedin/datafu