代码之家  ›  专栏  ›  技术社区  ›  Dave Funk

一种生成具有3列行的材料随机网格的算法

  •  0
  • Dave Funk  · 技术社区  · 6 年前

    我正在构建一个使用RedditAPI和OAuth的React应用程序。

    我正在使用MaterialUI,我正试图使用该组件构建一个具有动态生成的列宽值(最大值显然为3)的3列图像网格。

    获取的图像贴子数组中的第一项将被赋予1到3之间的随机数的键/值对。如果第一个项的值为,则第二个项将被赋予一个完成行的数字的键/值对!= 3。

    然后,它将重新开始,这个想法是每次加载网格时,它的第一个项可能是1列宽、2列宽或3列宽的整行,并且该算法应该相应地完成网格的其余部分,这意味着所有行必须加起来为3。

    我尝试过以多种方式处理post数组,从在循环外给数组中的前两个对象赋值,然后定义一个“last post”和“post before that”变量,试图找出一种使行相加的方法。我试着想出一套规则,可以使这项工作,不管阵列的位置,但似乎无法得到一个答案,没有几个边缘案件。

    makeTiles() {
        let posts = this.props.posts;
        let postsWithCols = [];
        posts[0].cols = Math.floor(Math.random() * 3 + 1);
        console.log(posts[0])
        postsWithCols.push(posts[0]);
        let previousPost = postsWithCols[postsWithCols.length - 1];
        switch(previousPost.cols) {
          case 1: 
          console.log('is1');
          posts[1].cols = Math.floor(Math.random() * 2 + 1);
          postsWithCols.push(posts[1]);
          break;
          case 2: 
          console.log('is2');
          posts[1].cols = 1;
          postsWithCols.push(posts[1]);
          break;
          case 3: 
          console.log('is3');
          posts[1].cols = Math.floor(Math.random() * 3 + 1);
          postsWithCols.push(posts[1]);
          break;
          default:
          console.log('something went wrong');
          break;
        }
        let postBeforeThat = postsWithCols[postsWithCols.length - 2];
        console.log(previousPost)
        console.log(postBeforeThat)
        console.log(postsWithCols)
      }
      render() {
        this.makeTiles();
        return (
          <div>
            open grid when i can get tileData figured out.
            {/* <ImageGrid tileData={this.makeTiles()} {...this.props}/> */}
          </div>
        );
      }
    }
    

    我做这类工作的唯一方法是,在第一个初始瓷砖之后,它在1和2之间保持交替。

    2 回复  |  直到 6 年前
        1
  •  0
  •   lemieuxster    6 年前

    这里有几个问题。首先,所呈现的代码实际上只会给您两个最大的后列值。没有循环或返回来填充更多的列。第二,我认为您要做的是,让它创建一个post数组,该数组也有列值,但该方法从不返回最终值( postsWithCols )我假设您仍然只需要一个包含列值的文章列表,而不需要将其进一步拆分为行。

    let posts = this.props.posts;
    
    // Const for the max
    const maxColumns = 3;
    
    // Variable to keep track of current remaining columns. 
    let remainingColumns = maxColumns;
    
    // Go over each post and return the post with cols in to a new array. 
    let postsWithCols = posts.map((post, index) => {
       // Special case, if last item, fill remaining
       if (index === posts.length - 1) {
          post.cols = remainingColumns;
          return post;
       }
    
       // Get a random number for the remaining columns for this row
       const cols = Math.floor(Math.random() * remainingColumns + 1);
       post.cols = cols;
    
       // Subtract the value
       remainingColumns = remainingColumns - cols;
    
       // If value is 0, reset to max. 
       if (remainingColumns <= 0) {
          remainingColumns = maxColumns;
       }
    
       // Add to result array
       return post;
    });
    
    console.log(postsWithCols); 
    

    关于这个问题还有很多可以调整的地方,但这是一般的想法。

        2
  •  0
  •   Dave Funk    6 年前

    我最终能找到解决办法。

          getPostsWithColumns = (posts) => {
        const postsWithColumns = posts.reduce((accum, post) => {
          const lastIndex = accum.length - 1;
          if (accum[lastIndex] && this.totalColumns(accum[lastIndex]) < 3) {
            const currentTotal = this.totalColumns(accum[lastIndex]);
            const postWithCols = {
              ...post,
              cols: currentTotal === 2 ? 1 : this.randomNumber(2)
            };
            accum[lastIndex] = [...accum[lastIndex], postWithCols];
            return accum;
          }
          const postWithCols = {
            ...post,
            cols: this.randomNumber(3)
          }
          return [...accum, [postWithCols]];
        }, []);
        return postsWithColumns.reduce((accum, group) => [...accum, ...group], []);
      };