javascript - Render a list of names alphabetically and grouped by their first char - Stack Overflow

I need to render a list of names alphabetically and grouped by the starting letter of each name. It sho

I need to render a list of names alphabetically and grouped by the starting letter of each name. It should look like this:

**A**

Anders
Anton
Angela

**B**

Brian
Bernard

**C**

Carl

My current solution can sort all the names that is contained within an object, but I am having trouble adding the starting letter as an element before the names (e.g. rendering 'A' above 'Anders' and 'B' above 'Brian')

Current solution:

pleteEmpList = empList
  .sort((a, b) => a.Name.localeCompare(b.Name))
    .map((emp) => (
      <div> {emp.Name} </div>
    ))

It is not supposed to handle data of more than a max of 300 elements, so optimization is not that important in this case.

I need to render a list of names alphabetically and grouped by the starting letter of each name. It should look like this:

**A**

Anders
Anton
Angela

**B**

Brian
Bernard

**C**

Carl

My current solution can sort all the names that is contained within an object, but I am having trouble adding the starting letter as an element before the names (e.g. rendering 'A' above 'Anders' and 'B' above 'Brian')

Current solution:

pleteEmpList = empList
  .sort((a, b) => a.Name.localeCompare(b.Name))
    .map((emp) => (
      <div> {emp.Name} </div>
    ))

It is not supposed to handle data of more than a max of 300 elements, so optimization is not that important in this case.

Share Improve this question edited Jun 8, 2018 at 6:24 Alyson Maia 8105 silver badges14 bronze badges asked Jun 7, 2018 at 19:46 BaconPancakesBaconPancakes 3957 silver badges21 bronze badges 6
  • Assuming the names are strings, after sorting, you can index them to obtain the first character, and utilize that to determine if you need a new starting letter group. – Andrew Fan Commented Jun 7, 2018 at 19:49
  • @HunterMcMillen, why do you edit the question like that? The desired output should not get code format. It is not code. – trincot Commented Jun 7, 2018 at 19:51
  • Group them first, iterate over the first letters (the properties of the object) in alphabetically order, for each letter print it and print the names in alphabetically order – Andreas Commented Jun 7, 2018 at 19:51
  • @AndrewFan Thanks, your answer helped me in the right direction. – BaconPancakes Commented Jun 7, 2018 at 20:06
  • No problem. I'm glad that you figured it out. – Andrew Fan Commented Jun 7, 2018 at 20:28
 |  Show 1 more ment

5 Answers 5

Reset to default 6

You could first sort and then use reduce to create one object and group your values by first char of each name.

var data = [
  { Name: 'Carl' },
  { Name: 'Anders' },
  { Name: 'Anton' },
  { Name: 'Brian' },
  { Name: 'Bernard' },
  { Name: 'Angelaa' },
];

const App = ({ data }) => {
  const parsedData = React.useMemo(() => {
    const obj = data.reduce((r, { Name }) => {
      const l = Name[0];
      if (!r[l]) r[l] = [Name];
      else r[l].push(Name);
      return r;
    }, {});

    const sorted = Object.entries(obj).sort(([a], [b]) => a.localeCompare(b));

    return sorted;
  }, [data]);

  return parsedData.map(([key, value]) => (
    <div key={key}>
      <strong>{key}</strong>
      <ul>
        {value.map(v => (
          <li key={v}>{v}</li>
        ))}
      </ul>
    </div>
  ));
};

ReactDOM.render(<App data={data} />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare./ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare./ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="root"></div>

With a bit of guidance from the ments, I made it work with this code:

let previousChar = ''

if (empList) {
  pleteEmpList = empList
    .sort((a, b) => a.Name.localeCompare(b.Name))
    .map((emp) => {
      if (emp.Name.charAt(0) !== previousChar) {
        previousChar = emp.Name.charAt(0)
        return (
            <div>
              <div className='charElement' key={'c' + emp.Id}> emp.Name.charAt(0)}</div>
            </div>
            <div>
              <div className='empName'>{emp.Name}</div>
            </div>
        )
      } else {
        return (
          <div className='empName'>{emp.Name}</div>
        )
      }
    })

You could try this code:

pleteEmpList = empList
  .sort((a, b) => a.Name.localeCompare(b.Name))
  .map((emp, index, array) => (
    <div> 
      { array[index - 1].Name[0].localeCompare( emp.Name[0] ) === -1?
        <p>** { emp.Name[0] } **</p>
      }
      {emp.Name}
    </div>
  ))

Another way to think about this is to do some data processing first to convert your data into a convenient format, and only then to create your view. Assuming you know how to generate your view from it, I would think a useful format might be an array of arrays, with one internal array for each initial letter, something like

[["Anders", "Angela", "Anton"], ["Bernard", "Brian"], ["Carl"]]

To create this, you could use a custom solution, but there is a reasonable abstraction that might be easier to write. So this version creates the function groupWith, which accepts a function that itself accepts two consecutive values and responds with whether they are part of the same group, in this case, just (a, b) => a.charAt(0) == b.charAt(0):

const groupWith = (fn, list) => list.slice(1).reduce(
  (all, curr) => fn(all[all.length - 1][0], curr) 
    ? all.slice(0, -1).concat([all[all.length - 1].concat(curr)])
    : all.concat([[curr]]), 
  [[list[0]]]
)

const names = ['Brian', 'Anders', 'Angela', 'Carl', 'Anton', 'Bernard'];

const groups = groupWith((a, b) => a.charAt(0) == b.charAt(0), names.sort())

console.log(groups)

The groupWith function can be reused across your projects, and it abstracts the messiness away from your more important code.

String Immutability makes Amortization Important.

I know you said optimization is not important, however, I would argue that it very much is important when working with Strings. Reason being "immutability". It's VERY easy to end up with a quadratic amortized time if one allows their algo to re-write strings upon every iteration. Using a collection, and inserting the strings into that collection with the necessary formatting (newline characters, etc.) is the cheapest and least-expensive way.

const names = ['Brian', 'Anders', 'Angela', 'Carl', 'Anton', 'Bernard'];

// Create a primative hashtable with the Alphabetized letter as your key.
// Your value for that key, is a collection of the Names.
const memo = names.reduce((memo, name) => {
  if (name[0] in memo) memo[name[0]].push(name);     // if the first letter in the name has already been recorded, then add it to the collection in that letter.
  else memo[name[0]] = [name];                       // if the first letter has yet to be added to the memo, add the letter and assign createa a new collection of names.

  return memo;
}, {});
console.log('memo: ', memo)

// Now iterate over your memoized collection.
// Strings are immutable so using arrays of individual words are best for the 
// lowest runtime. Otherwise, you'll have quadratic amortized time.
const answer = Object
  .keys(memo)
  .sort()                              // Sort the memo keys to ensure alphabetical order.
  .reduce((a, letter) => {             // Reduce a memo {object} into an array...
    const letterList = memo[letter]    // Create new array of names.
      .sort()                          // sorting the array of names.
      .map((name) => name);            // Return each name into the array.

    letterList.unshift(`**${letter}**`, '\n');  // "unshift" puts the insertion value in the front of the collection.
    letterList.push('\n');                      // add a newline to the end of the array to seperate the individual letter groups.

  a = a.concat(letterList);                     // add the finished Letter array to the overall collection of all names.

  return a;
}, [])
.join('\n');                                    // Join on newline so that you don't have to re-write the entire string due to immutability.

console.log('Answer: \n', answer);

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744874546a4598468.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信