0

The array of objects I want to filter/search looks somewhat like this:

var array = [
 {  
    id: 62,
    title: "sometitle",
    text: „aaaaaaaaaaaaaaa“,
    keywords: ["other", "Party", "Shanghai"],
    read: false
},
{   
    id: 63,
    title: "othertitle",
    text: "bbbbbbbbbbbbbbbbbb",
    keywords: ["Party", "Shanghai", "Seo-Yeon"],
    read: false
},
{   
    id: 64,
    title: "againothertitle",
    text: "ccccccccccccccccccc",
    keywords: ["Chinesisch", "Alltag", "other"],
    read: false
}];

I want to select one random value of an object and filter the whole array to find other objects that share this one specific value - except for the current object of course. To be more precise I want to filter the array with one of the „keywords“. The current object should be spliced from the array. Also underneath the current object I want to display buttons that each contain the title of the object that shares the keyword. When the user clicks on one oft he buttons the according object should be selected, shown, again sliced from array. Again one of this selected object’s keywords should be randomly selected to filter the rest of the array with. This is what the implementation should look like:it looks right but doesnt behave right^^

This is the html:

<body>
    <div id="container-fluid">
        <h2 id="title"></h2>
        <div id="output"></div> 
        <div id="button-container"></div>
     </div>      
    <script type="text/javascript" src="src/js/snu.js"></script>
    <script type="text/javascript" src="src/js/index.js"></script>
</body>

And this the JS:

var startKeywords = [];
var btnContainer = document.getElementById('button-container');
var title = document.getElementById('title');
var output = document.getElementById('output');
var container = document.getElementById('container-fluid');
var result = [];
var nextSnusButtons = [];
var button = [];
//select a random SNU
var randomIndex = Math.floor(Math.random() * snus.length); 

(function first() {
    //showing the first random scene
    var start = snus[randomIndex];
    title.innerHTML = start.title;
    title.id = start.id;
    output.innerHTML = start.text;
    start.read = true;
    cache.push(start);

    startKeywords = start.keywords;

    var randomStartKeyIndex = Math.floor(Math.random() * startKeywords.length); 
    var randomStartKey = startKeywords[randomStartKeyIndex];

    //create a filter
    function filterNextSet(val){
        var randomValueKeyIndex = Math.floor(Math.random() * val.keywords.length);
        var randomValueKey = val.keywords[randomValueKeyIndex];
        if (randomStartKey === val.keywords[0] || randomStartKey ===val.keywords[1] || randomStartKey === val.keywords[2] || randomStartKey === val.keywords[3] && randomStartKey.read === false) {
            return val
        }
    }

    //apply filter
    result = snus.filter(filterNextSet);
    var resultFirst = result[0];
    var resultLastIndex = result.length -1;
    var resultLast = result[resultLastIndex];
    var resultRandomIndex = Math.floor(Math.random() * result.length); 
    var resultRandom = result[resultRandomIndex];

    //generate HTML
    if(resultFirst.id  || resultRandom.id  || resultLast.id) {
        nextSnusButtons.push(resultFirst, resultRandom, resultLast);
        nextSnusButtons.forEach(function(nextSnu) {
            button = document.createElement('button');
            button.id = nextSnu.id;
            button.innerHTML = nextSnu.title;
            btnContainer.append(button);
        });
    }
})();

I have been using plain javascript to solve this problem for days but I only find myself in Spghetti code. I feel like I am constnatly repeating stuff and that this is not gonna end. I would really appreciate your help! Should I use React instead?? Thank You very much in advance!

Barmar
  • 741,623
  • 53
  • 500
  • 612
Jules
  • 23
  • 5
  • This post https://stackoverflow.com/questions/10679580/javascript-search-inside-a-json-object can help you!! – MKR Sep 15 '17 at 22:51
  • @MKR Uh! Thanks, will check it out :) – Jules Sep 15 '17 at 23:02
  • Your trying to ask too many questions here,. What I would suggest is we break this down. First lets sort the array filtering problem, & not worry about the random bit. I'm assuming from your description if item 62 was selected, 63 & 64. But if 63 was selected 62 would be returned, and for 64 again 62 would be returned,. Because in each case they have the same keyword, is that correct? – Keith Sep 15 '17 at 23:04
  • Yes, that's correct! :) – Jules Sep 15 '17 at 23:18
  • Ok, I'll post a simple example doing that bit.. – Keith Sep 15 '17 at 23:20

2 Answers2

0

Ok,

Here a simple example of doing the first part (filtering the data).

In this example at the end I'm just showing the match for every combo, in your case you can just call the getForArrayItem with your random number.

var array = [
 {  
    id: 62,
    title: "sometitle",
    text: "aaaaaaaaaaaaaa",
    keywords: ["other", "Party", "Shanghai"],
    read: false
},
{   
    id: 63,
    title: "othertitle",
    text: "bbbbbbbbbbbbbbbbbb",
    keywords: ["Party", "Shanghai", "Seo-Yeon"],
    read: false
},
{   
    id: 64,
    title: "againothertitle",
    text: "ccccccccccccccccccc",
    keywords: ["Chinesisch", "Alltag", "other"],
    read: false
}];

function getForArrayItem(idx) {
  let 
    item = array[idx],
    iset = new Set(item.keywords);
  return array.filter((i) => {
    //first don't include self
    if (i === item) return false;
    //now see if any of the keyword exist in this
    return i.keywords.some(x => iset.has(x));
  });
}

array.forEach((item, ix) => {
  console.log('ITEM ' + item.id + ' = ' +
     getForArrayItem(ix).map((i)=>i.id).join(', '));
});

Here is a snippet just using ES5 constructs. Also I've not used any forEach, some, filter.. just for loops..

var array = [
 {  
    id: 62,
    title: "sometitle",
    text: "aaaaaaaaaaaaaa",
    keywords: ["other", "Party", "Shanghai"],
    read: false
},
{   
    id: 63,
    title: "othertitle",
    text: "bbbbbbbbbbbbbbbbbb",
    keywords: ["Party", "Shanghai", "Seo-Yeon"],
    read: false
},
{   
    id: 64,
    title: "againothertitle",
    text: "ccccccccccccccccccc",
    keywords: ["Chinesisch", "Alltag", "other"],
    read: false
}];

function getForArrayItem(idx) {
  var 
    item = array[idx],
    iset = {},
    ret = [],
    l;
  //first lets store a set of fast lookup keywords
  //we could use indexOf, but this should be faster
  for (l = 0; l < item.keywords.length; l++)
    iset[item.keywords[l]] = true;    
  //now loop through all arrays
  for (l = 0; l < array.length; l ++) {
    //lets not include our self
    if (l === idx) continue;
    var aitem = array[l], any = false;
    //now ltes see if any of keywords exist in our iset lookup
    for (var lc = 0; lc < aitem.keywords.length; lc++) {
      var keyword = aitem.keywords[lc];
      if (iset[keyword]) {
        ret.push(aitem);
        break;
      }
    }
    if (any) ret.push(item);
  }
  return ret;
}

for (var ix = 0; ix < array.length; ix ++) {
  var items = getForArrayItem(ix);
  var id_items = [];
  for (var ll = 0; ll < items.length; ll++) id_items.push(items[ll].id);
  console.log('ITEM ' + array[ix].id + ' = ' + id_items.join(', '));
}
Keith
  • 22,005
  • 2
  • 27
  • 44
0

This is my solution:

function selectRandomKeyword(obj) {
  const max = obj['keywords'].length;
  const random = Math.floor(Math.random() * max);
  return obj['keywords'][random];
}

function findObjsWithKeyword(array, keyword) {
  const foundArray = [];
  array.forEach(obj => {
    if (obj['keywords'].includes(keyword)) {
      foundArray.push(obj);
    }
  });
  return foundArray;
}

const selectedObj = (array[0]);

const keyword = selectRandomKeyword(selectedObj);

const newObjs = findObjsWithKeyword(array, keyword);

So newObjs will have your new array with only the matching randomly selected keyword. And if you want to remove the selectedObj:

var index = newObjs.indexOf(selectedObj);

newObjs.splice(index, 1);

newObjs;
  • This is also nice! I never would've thought of something like this: obj['keywords'][random] .... Thank you – Jules Sep 16 '17 at 10:46
  • I have tried your code and I have managed to loop thru the newObjs to create Buttons with the title of each Object that shares a keyword with the current object. Looping through I have attached an evenlistener that obtains the id of each button/object. But somehow I cannot obtain the object! – Jules Sep 16 '17 at 15:01
  • If i knew how to obtain the objeact that is hidden behind that id, I could set it equal to selectedObj and the code could start to execute "from the beginning" sort of. That would be so nice but I am stuck again... any ideas? This is my status quo: https://github.com/julibi/shonagonproject/commit/a1442d345a5f09489c17345fa94b26d1056556e3 – Jules Sep 16 '17 at 15:04
  • I'll check out the github repo later tonight and try to help. – Andrew Harris Sep 16 '17 at 23:08