Intermediate Algorithm Scripting: Wherefore art thou ... trouble understanding solution

The solution code:

function whatIsInAName(collection, source) {
  
  var srcKeys = Object.keys(source);
 
  // filter the collection
  return collection.filter(function (obj) {
    for(var i = 0; i < srcKeys.length; i++) {
      if(!obj.hasOwnProperty(srcKeys[i]) || obj[srcKeys[i]] !== source[srcKeys[i]]) {
        return false;
      }
    }
    return true;
  });
}

What I don’t get about this answer is that it appears to just be returning true or false. The directions in the exercise says to return the specific cases in collection that pass the test.

whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" }) should return [{ first: "Tybalt", last: "Capulet" }]

What am I missing here?

Hello, what you are missing is this:

return collection.filter(function(obj) {
    // The code that returns true or false you are referring to
});

What whatIsInAName() is returning is the value returned by this filter function, which is an array of objects that have been each tested against the true/false test you noted. If an object passes (returns true) it is included. If it fails (returns false) it is filtered out.

I tried to at least extract the function that feeds filter() to make it more comprehendable. I’d probably just try to never use filter since it seems complicated and ugly.

<script>

function wtf(obj){
	for(var i = 0; i < srcKeys.length; i++) {
		if(!obj.hasOwnProperty(srcKeys[i]) || obj[srcKeys[i]] !== source[srcKeys[i]]) {
			return false;
		}
	}
	return true; //stupid optional semi colons
}//stupid curly brackets where u have to press up+tab every time u use them which is always

//had to make this global or wtf did not recognize it
var srcKeys
function whatIsInAName(collection, source) {
  srcKeys = Object.keys(source)
  // filter the collection
  return collection.filter(wtf) //apparently no way to send parameters to wtf, so had to use globals
	//thats some ugly ass shit feeding a function w no allowable parameters as a parameter to another function
	//id rather make my own filter function than use this crap. next time u try to use it youll forget how and have to analyze it an hour again
}

//had to make these 2 globals or wtf() did not recognize them
collection=[{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }]
source={last: "Capulet"}

a=whatIsInAName(collection,source) 
for(i=0;i<a.length;i++){
	console.log(a[i])
}

//filter() creates new array w all elements that pass the test implemented by the provided function.
</script>

You will change idea, high order functions are useful, some challenges become extremely complicated without using them.
The filter() method iterate over each item in the array and keeps only those for which the callback returns true

filteredArray = [0,1,2,3,4,5,6,7].filter(x => x % 2 === 1)
Simple way to get an array with only odd numbers.

written with es5;
`filteredArray = [0,1,2,3,4,5,6,7].filter(function(x) { return x % 2 === 1; }

When you don’t remember how something works (and you don’t have!), reading documentation is really useful:

This is how I’d try to filter stuff, no arrow functions or fancy function parameters, just simplicity that anyone coming from any language background would probably understand quickly.

<script>
function filterByLength(wordlist,minlen,maxlen){
	ret=[]
	for(i=0;i<wordlist.length;i++){
		if(wordlist[i].length>=minlen && wordlist[i].length<=maxlen){
			ret.push(wordlist[i])
		}
	}
	return ret
}
function even(n){
	if(n%2==0) return true
	return false
}

words=['abc','abcd','abcde','abcdef','abcdefg','abcdefgh']
filtwords=filterByLength(words,4,7)
console.log(filtwords)

ns=[7,5,6,8,3,2]
for(i=ns.length-1;i>-1;i--){//backwards since deleting shortens array
	if(!even(ns[i])){
	//if(ns[i]%2!=0){  //really id do it like this and not even make an even() function
		ns.splice(i,1)
	}
}
console.log(ns)

</script>

Another really convoluted thing in javascript is canvas. In python & pygame, you simply make a Surface() and draw a pixel right on it (I think mysurf.putat((0,0),color) or something simple.
With javascript… first you make a canvas… then you make a context for the canvas… then you make a imageData for the context… then you make a Data for the image data. FINALLY you can draw a pixel on that data. That’s 4 nested objects and seems totally insane and complicated to me. You should just draw right on the canvas without even a context, let alone the other 2. Since there’s 4 things you constantly have to look up which thing is used in which functions and has which methods. And if you want a list of 20 canvases to draw pixels on each, you need all 4 things each (I think) so 80 objects instead of 20. What a mess.

It seems unnecessary complex for something for which you have already a method that you can use.

But if you don’t like JavaScript, learn an other language, there are so many out there…

Ahh you know what I actually get it now!

@ChadKreutzer Thanks for pointing that out. What I was missing was the return in front of the filter.

return collection.filter(function(obj)

But even had I caught that the:

collection.filter(function (obj) {

was a bit dense and hard to decipher what was really going on.

@wtf Thanks for breaking that down and I will probably do something similar in the future. I understand now that filter returns the true cases of what ever test you decide to write. In which case you can build a test as a function that returns true/false and just feed that function into the filter. I get it!

Perhaps before ripping into a tool, learn how to use it:

function wtf(obj, srcKeys) {
  for (var i = 0; i < srcKeys.length; i++) {
    if (!obj.hasOwnProperty(srcKeys[i]) || obj[srcKeys[i]] !== source[srcKeys[i]]) {
      return false;
    }
  }
  return true; // just use em. :slight_smile: 
} // brackets are common to most C derived languages. And personally I prefer them to trying to keep track of indentation, but to each their own.

function whatIsInAName(collection, source) {
  const srcKeys = Object.keys(source)
  // filter the collection
  return collection.filter(obj => wtf(obj, srcKeys)); // no global and easily passing parameter in to wtf
}

// of course these are global. they are the data being passed into whatIsInAName to be used by wtf inside there.
const collection = [{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }]
const source = { last: "Capulet" }

const a = whatIsInAName(collection, source)
for (i = 0; i < a.length; i++) {
  console.log(a[i])
}

If you comment out const collection and const source and change
const a = whatIsInAName(collection, source)
to the direct values:
const a = whatIsInAName([{ first: “Romeo”, last: “Montague” }, { first: “Mercutio”, last: null }, { first: “Tybalt”, last: “Capulet” }], { last: “Capulet” } )
then it says:
ReferenceError: source is not defined

Here’s a question.
say i type this:
function a(){
(cursor here already)
}
I want to type the first bracket, and have the text automatically type the 2nd bracket AND put my cursor 1 line above with an indent. Is there anything that does that? Notepad++ doesn’t seem to. Otherwise I have to type left bracket,enter,enter,right bracket,up,tab, for EVERY function/if etc, that’s a horrible workload, python doesn’t multiply your workload by 6 input characters for every for/if.

But most importantly, if you’re good at javascript, can you please tell me why the heck I can’t see a png on my screen with the following code? I can see the png if I use a single canvas (commented out parts) but with an array of canvases, I don’t see a png, I’m stumped. I even put a red fill on there. I see the red fill of a 60x30 area, but no png. I can paste a link to the pngs if you need to test w them. (or just make 18 60wx30h pngs w pixels on transparent background named snake0.png to snake17.png. I see the png on the single canvas just not in the array, so the pngs aren’t the problem

also I purposely made that i variable global, but I still have to feed the i as a parameter to the nameless function or it seems to have weird garbage values. I thought i was global so the nameless function should see it without feeding i as a parameter.

<script>

function main(){
	if (paused==false){
		ctx.fillStyle='rgb(128,128,128)'
		ctx.fillRect(0,0,canvas.width,canvas.height)
		ctx2.fillStyle='rgb(255,255,255)'
		ctx2.fillRect(0,0,canvas2.width,canvas2.height)
		
		ctx2.drawImage(snakecans[1],0,0) //does not work with array (comment out the opposite line and block below when testing)
		//ctx2.drawImage(snakecan,0,0) //does work (no array)
		
		ctx.drawImage(canvas2,0,0,canvas2.width,canvas2.height,  5,5,canvas2.width,canvas2.height)
	}
}

canvas=document.getElementById('canvas')
ctx=canvas.getContext('2d')
canvas2=document.createElement('canvas')
canvas2.width=540
canvas2.height=540
ctx2=canvas2.getContext('2d')

//does not work (comment out opposite block and line above when testing)
//can't see any png on screen

//i have 18 pngs. i want to put them in 18 'canvases' (so i guess i need 18 contexts too)
snakecans=[]
snakectxs=[]
var i=0
for(i=0;i<18;i++){
	snakecans.push(document.createElement('canvas'))
	snakecans[i].width=60
	snakecans[i].height=30
	snakectxs.push(snakecans[i].getContext('2d'))
	im=new Image()
	im.src='snake'+String(i)+'.png'
	im.onload=function(i,snakectxs){ //you apparently need this onload or the png wont load in time
		console.log(i)
		snakectxs[i].fillStyle='rgb(255,0,0)'
		snakectxs[i].fillRect(0,0,snakecans[i].width,snakecans[i].height)
		snakectxs[i].drawImage(im,0,0)
	}(i,snakectxs) //says 'snakectxs[i] is undefined' unless I put that stuff in parentheses
}



//does work
//can see png on screen
/*
snakecan=document.createElement('canvas')
snakecan.width=60
snakecan.height=30
snakectx=snakecan.getContext('2d')
im=new Image()
im.src='snake'+String(3)+'.png'
im.onload=function(){
	snakectx.drawImage(im,0,0)
}
*/




paused=false
setInterval(main, 1000/60)
</script>

I’d be curious to see your code, because I just tried doing that very thing and it worked fine for me.

As far as your canvas question, I am pretty good at JS, but honestly, I haven’t done much image manipulation. Lemme look into it and I’ll get back to you (unless someone else beats me to it.)

To your question about typing in the brackets. Try VS Code. for your example, if I type:

function a()

The next thing I type is { then I hit enter and it ends up like this:

function a(){
    // my cursor is here
}

it automatically puts my cursor where I want it to be (and I can adjust the setting for how much it wants to indent) and adds the closing bracket.

I edited it till it worked, using your thick arrow instant-nameless-function-whatjamacall. I probably had trouble with my previous version that had no way to get parameters to wtf like yours.

I’ll try vs code as soon as I can solve this png thing. Trying to make a web game so have to use javascript/html5/canvas instead of python (and for whatever political reason the new world order seems to be strangling flash to death)

<script>
function wtf(collection,source,srcKeys) {
  for (i = 0; i < srcKeys.length; i++) {
    if (!collection.hasOwnProperty(srcKeys[i]) || collection[srcKeys[i]] !== source[srcKeys[i]]) {
      return false;
    }
  }
  return true
}

function whatIsInAName(collection, source) {
  srcKeys = Object.keys(source)
  return collection.filter(collection => wtf(collection,source,srcKeys))
}

a = whatIsInAName([{ first: "Romeo", last: "Montague" }, { first: "Mercutio", last: null }, { first: "Tybalt", last: "Capulet" }], { last: "Capulet" })
for (i = 0; i < a.length; i++) {
  console.log(a[i])
}
</script>